Remove smbmount.
[Samba/gebeck_regimport.git] / source3 / utils / net_ads.c
blob345665d62eec0a072b8faf1bf11755b78ac17c08
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"
26 #include "libnet/libnet.h"
28 #ifdef HAVE_ADS
30 int net_ads_usage(int argc, const char **argv)
32 d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
33 d_printf(" Join the local machine to a ADS realm\n");
34 d_printf("leave\n");
35 d_printf(" Remove the local machine from a ADS realm\n");
36 d_printf("testjoin\n");
37 d_printf(" Validates the machine account in the domain\n");
38 d_printf("user\n");
39 d_printf(" List, add, or delete users in the realm\n");
40 d_printf("group\n");
41 d_printf(" List, add, or delete groups in the realm\n");
42 d_printf("info\n");
43 d_printf(" Displays details regarding a specific AD server\n");
44 d_printf("status\n");
45 d_printf(" Display details regarding the machine's account in AD\n");
46 d_printf("lookup\n");
47 d_printf(" Performs CLDAP query of AD domain controllers\n");
48 d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
49 d_printf(" Change a user's password using an admin account\n");
50 d_printf(" (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
51 d_printf("changetrustpw\n");
52 d_printf(" Change the trust account password of this machine in the AD tree\n");
53 d_printf("printer [info | publish | remove] <printername> <servername>\n");
54 d_printf(" Lookup, add, or remove directory entry for a printer\n");
55 d_printf("{search,dn,sid}\n");
56 d_printf(" Issue LDAP search queries using a general filter, by DN, or by SID\n");
57 d_printf("keytab\n");
58 d_printf(" Manage a local keytab file based on the machine account in AD\n");
59 d_printf("dns\n");
60 d_printf(" Issue a dynamic DNS update request the server's hostname\n");
61 d_printf(" (using the machine credentials)\n");
63 return -1;
66 /* when we do not have sufficient input parameters to contact a remote domain
67 * we always fall back to our own realm - Guenther*/
69 static const char *assume_own_realm(void)
71 if (!opt_host && strequal(lp_workgroup(), opt_target_workgroup)) {
72 return lp_realm();
75 return NULL;
79 do a cldap netlogon query
81 static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
83 char addr[INET6_ADDRSTRLEN];
84 struct cldap_netlogon_reply reply;
85 struct GUID tmp_guid;
87 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
88 if ( !ads_cldap_netlogon(addr, ads->server.realm, &reply ) ) {
89 d_fprintf(stderr, "CLDAP query failed!\n");
90 return -1;
93 d_printf("Information for Domain Controller: %s\n\n",
94 addr);
96 d_printf("Response Type: ");
97 switch (reply.type) {
98 case SAMLOGON_AD_UNK_R:
99 d_printf("SAMLOGON\n");
100 break;
101 case SAMLOGON_AD_R:
102 d_printf("SAMLOGON_USER\n");
103 break;
104 default:
105 d_printf("0x%x\n", reply.type);
106 break;
109 smb_uuid_unpack(reply.guid, &tmp_guid);
110 d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), tmp_guid));
112 d_printf("Flags:\n"
113 "\tIs a PDC: %s\n"
114 "\tIs a GC of the forest: %s\n"
115 "\tIs an LDAP server: %s\n"
116 "\tSupports DS: %s\n"
117 "\tIs running a KDC: %s\n"
118 "\tIs running time services: %s\n"
119 "\tIs the closest DC: %s\n"
120 "\tIs writable: %s\n"
121 "\tHas a hardware clock: %s\n"
122 "\tIs a non-domain NC serviced by LDAP server: %s\n",
123 (reply.flags & ADS_PDC) ? "yes" : "no",
124 (reply.flags & ADS_GC) ? "yes" : "no",
125 (reply.flags & ADS_LDAP) ? "yes" : "no",
126 (reply.flags & ADS_DS) ? "yes" : "no",
127 (reply.flags & ADS_KDC) ? "yes" : "no",
128 (reply.flags & ADS_TIMESERV) ? "yes" : "no",
129 (reply.flags & ADS_CLOSEST) ? "yes" : "no",
130 (reply.flags & ADS_WRITABLE) ? "yes" : "no",
131 (reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
132 (reply.flags & ADS_NDNC) ? "yes" : "no");
134 printf("Forest:\t\t\t%s\n", reply.forest);
135 printf("Domain:\t\t\t%s\n", reply.domain);
136 printf("Domain Controller:\t%s\n", reply.hostname);
138 printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
139 printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
141 if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
142 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
144 printf("Server Site Name :\t\t%s\n", reply.server_site_name);
145 printf("Client Site Name :\t\t%s\n", reply.client_site_name);
147 d_printf("NT Version: %d\n", reply.version);
148 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
149 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
151 return 0;
155 this implements the CLDAP based netlogon lookup requests
156 for finding the domain controller of a ADS domain
158 static int net_ads_lookup(int argc, const char **argv)
160 ADS_STRUCT *ads;
162 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
163 d_fprintf(stderr, "Didn't find the cldap server!\n");
164 return -1;
167 if (!ads->config.realm) {
168 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
169 ads->ldap.port = 389;
172 return net_ads_cldap_netlogon(ads);
177 static int net_ads_info(int argc, const char **argv)
179 ADS_STRUCT *ads;
180 char addr[INET6_ADDRSTRLEN];
182 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
183 d_fprintf(stderr, "Didn't find the ldap server!\n");
184 return -1;
187 if (!ads || !ads->config.realm) {
188 d_fprintf(stderr, "Didn't find the ldap server!\n");
189 return -1;
192 /* Try to set the server's current time since we didn't do a full
193 TCP LDAP session initially */
195 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
196 d_fprintf( stderr, "Failed to get server's current time!\n");
199 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
201 d_printf("LDAP server: %s\n", addr);
202 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
203 d_printf("Realm: %s\n", ads->config.realm);
204 d_printf("Bind Path: %s\n", ads->config.bind_path);
205 d_printf("LDAP port: %d\n", ads->ldap.port);
206 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
208 d_printf("KDC server: %s\n", ads->auth.kdc_server );
209 d_printf("Server time offset: %d\n", ads->auth.time_offset );
211 return 0;
214 static void use_in_memory_ccache(void) {
215 /* Use in-memory credentials cache so we do not interfere with
216 * existing credentials */
217 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
220 static ADS_STATUS ads_startup_int(bool only_own_domain, uint32 auth_flags, ADS_STRUCT **ads_ret)
222 ADS_STRUCT *ads = NULL;
223 ADS_STATUS status;
224 bool need_password = False;
225 bool second_time = False;
226 char *cp;
227 const char *realm = NULL;
228 bool tried_closest_dc = False;
230 /* lp_realm() should be handled by a command line param,
231 However, the join requires that realm be set in smb.conf
232 and compares our realm with the remote server's so this is
233 ok until someone needs more flexibility */
235 *ads_ret = NULL;
237 retry_connect:
238 if (only_own_domain) {
239 realm = lp_realm();
240 } else {
241 realm = assume_own_realm();
244 ads = ads_init(realm, opt_target_workgroup, opt_host);
246 if (!opt_user_name) {
247 opt_user_name = "administrator";
250 if (opt_user_specified) {
251 need_password = True;
254 retry:
255 if (!opt_password && need_password && !opt_machine_pass) {
256 opt_password = net_prompt_pass(opt_user_name);
257 if (!opt_password) {
258 ads_destroy(&ads);
259 return ADS_ERROR(LDAP_NO_MEMORY);
263 if (opt_password) {
264 use_in_memory_ccache();
265 SAFE_FREE(ads->auth.password);
266 ads->auth.password = smb_xstrdup(opt_password);
269 ads->auth.flags |= auth_flags;
270 SAFE_FREE(ads->auth.user_name);
271 ads->auth.user_name = smb_xstrdup(opt_user_name);
274 * If the username is of the form "name@realm",
275 * extract the realm and convert to upper case.
276 * This is only used to establish the connection.
278 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
279 *cp++ = '\0';
280 SAFE_FREE(ads->auth.realm);
281 ads->auth.realm = smb_xstrdup(cp);
282 strupper_m(ads->auth.realm);
285 status = ads_connect(ads);
287 if (!ADS_ERR_OK(status)) {
289 if (NT_STATUS_EQUAL(ads_ntstatus(status),
290 NT_STATUS_NO_LOGON_SERVERS)) {
291 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
292 ads_destroy(&ads);
293 return status;
296 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
297 need_password = True;
298 second_time = True;
299 goto retry;
300 } else {
301 ads_destroy(&ads);
302 return status;
306 /* when contacting our own domain, make sure we use the closest DC.
307 * This is done by reconnecting to ADS because only the first call to
308 * ads_connect will give us our own sitename */
310 if ((only_own_domain || !opt_host) && !tried_closest_dc) {
312 tried_closest_dc = True; /* avoid loop */
314 if (!ads->config.tried_closest_dc) {
316 namecache_delete(ads->server.realm, 0x1C);
317 namecache_delete(ads->server.workgroup, 0x1C);
319 ads_destroy(&ads);
320 ads = NULL;
322 goto retry_connect;
326 *ads_ret = ads;
327 return status;
330 ADS_STATUS ads_startup(bool only_own_domain, ADS_STRUCT **ads)
332 return ads_startup_int(only_own_domain, 0, ads);
335 ADS_STATUS ads_startup_nobind(bool only_own_domain, ADS_STRUCT **ads)
337 return ads_startup_int(only_own_domain, ADS_AUTH_NO_BIND, ads);
341 Check to see if connection can be made via ads.
342 ads_startup() stores the password in opt_password if it needs to so
343 that rpc or rap can use it without re-prompting.
345 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
347 ADS_STRUCT *ads;
348 ADS_STATUS status;
350 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
351 return -1;
354 ads->auth.flags |= ADS_AUTH_NO_BIND;
356 status = ads_connect(ads);
357 if ( !ADS_ERR_OK(status) ) {
358 return -1;
361 ads_destroy(&ads);
362 return 0;
365 int net_ads_check_our_domain(void)
367 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
370 int net_ads_check(void)
372 return net_ads_check_int(NULL, opt_workgroup, opt_host);
376 determine the netbios workgroup name for a domain
378 static int net_ads_workgroup(int argc, const char **argv)
380 ADS_STRUCT *ads;
381 char addr[INET6_ADDRSTRLEN];
382 struct cldap_netlogon_reply reply;
384 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
385 d_fprintf(stderr, "Didn't find the cldap server!\n");
386 return -1;
389 if (!ads->config.realm) {
390 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
391 ads->ldap.port = 389;
394 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
395 if ( !ads_cldap_netlogon(addr, ads->server.realm, &reply ) ) {
396 d_fprintf(stderr, "CLDAP query failed!\n");
397 return -1;
400 d_printf("Workgroup: %s\n", reply.netbios_domain);
402 ads_destroy(&ads);
404 return 0;
409 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
411 char **disp_fields = (char **) data_area;
413 if (!field) { /* must be end of record */
414 if (disp_fields[0]) {
415 if (!strchr_m(disp_fields[0], '$')) {
416 if (disp_fields[1])
417 d_printf("%-21.21s %s\n",
418 disp_fields[0], disp_fields[1]);
419 else
420 d_printf("%s\n", disp_fields[0]);
423 SAFE_FREE(disp_fields[0]);
424 SAFE_FREE(disp_fields[1]);
425 return True;
427 if (!values) /* must be new field, indicate string field */
428 return True;
429 if (StrCaseCmp(field, "sAMAccountName") == 0) {
430 disp_fields[0] = SMB_STRDUP((char *) values[0]);
432 if (StrCaseCmp(field, "description") == 0)
433 disp_fields[1] = SMB_STRDUP((char *) values[0]);
434 return True;
437 static int net_ads_user_usage(int argc, const char **argv)
439 return net_help_user(argc, argv);
442 static int ads_user_add(int argc, const char **argv)
444 ADS_STRUCT *ads;
445 ADS_STATUS status;
446 char *upn, *userdn;
447 LDAPMessage *res=NULL;
448 int rc = -1;
449 char *ou_str = NULL;
451 if (argc < 1) return net_ads_user_usage(argc, argv);
453 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
454 return -1;
457 status = ads_find_user_acct(ads, &res, argv[0]);
459 if (!ADS_ERR_OK(status)) {
460 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
461 goto done;
464 if (ads_count_replies(ads, res)) {
465 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
466 goto done;
469 if (opt_container) {
470 ou_str = SMB_STRDUP(opt_container);
471 } else {
472 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
475 status = ads_add_user_acct(ads, argv[0], ou_str, opt_comment);
477 if (!ADS_ERR_OK(status)) {
478 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
479 ads_errstr(status));
480 goto done;
483 /* if no password is to be set, we're done */
484 if (argc == 1) {
485 d_printf("User %s added\n", argv[0]);
486 rc = 0;
487 goto done;
490 /* try setting the password */
491 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
492 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
493 ads->auth.time_offset);
494 safe_free(upn);
495 if (ADS_ERR_OK(status)) {
496 d_printf("User %s added\n", argv[0]);
497 rc = 0;
498 goto done;
501 /* password didn't set, delete account */
502 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
503 argv[0], ads_errstr(status));
504 ads_msgfree(ads, res);
505 status=ads_find_user_acct(ads, &res, argv[0]);
506 if (ADS_ERR_OK(status)) {
507 userdn = ads_get_dn(ads, res);
508 ads_del_dn(ads, userdn);
509 ads_memfree(ads, userdn);
512 done:
513 if (res)
514 ads_msgfree(ads, res);
515 ads_destroy(&ads);
516 SAFE_FREE(ou_str);
517 return rc;
520 static int ads_user_info(int argc, const char **argv)
522 ADS_STRUCT *ads;
523 ADS_STATUS rc;
524 LDAPMessage *res;
525 const char *attrs[] = {"memberOf", NULL};
526 char *searchstring=NULL;
527 char **grouplist;
528 char *escaped_user;
530 if (argc < 1) {
531 return net_ads_user_usage(argc, argv);
534 escaped_user = escape_ldap_string_alloc(argv[0]);
536 if (!escaped_user) {
537 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
538 return -1;
541 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
542 SAFE_FREE(escaped_user);
543 return -1;
546 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
547 rc = ads_search(ads, &res, searchstring, attrs);
548 safe_free(searchstring);
550 if (!ADS_ERR_OK(rc)) {
551 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
552 ads_destroy(&ads);
553 SAFE_FREE(escaped_user);
554 return -1;
557 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
558 (LDAPMessage *)res, "memberOf");
560 if (grouplist) {
561 int i;
562 char **groupname;
563 for (i=0;grouplist[i];i++) {
564 groupname = ldap_explode_dn(grouplist[i], 1);
565 d_printf("%s\n", groupname[0]);
566 ldap_value_free(groupname);
568 ldap_value_free(grouplist);
571 ads_msgfree(ads, res);
572 ads_destroy(&ads);
573 SAFE_FREE(escaped_user);
574 return 0;
577 static int ads_user_delete(int argc, const char **argv)
579 ADS_STRUCT *ads;
580 ADS_STATUS rc;
581 LDAPMessage *res = NULL;
582 char *userdn;
584 if (argc < 1) {
585 return net_ads_user_usage(argc, argv);
588 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
589 return -1;
592 rc = ads_find_user_acct(ads, &res, argv[0]);
593 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
594 d_printf("User %s does not exist.\n", argv[0]);
595 ads_msgfree(ads, res);
596 ads_destroy(&ads);
597 return -1;
599 userdn = ads_get_dn(ads, res);
600 ads_msgfree(ads, res);
601 rc = ads_del_dn(ads, userdn);
602 ads_memfree(ads, userdn);
603 if (ADS_ERR_OK(rc)) {
604 d_printf("User %s deleted\n", argv[0]);
605 ads_destroy(&ads);
606 return 0;
608 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
609 ads_errstr(rc));
610 ads_destroy(&ads);
611 return -1;
614 int net_ads_user(int argc, const char **argv)
616 struct functable func[] = {
617 {"ADD", ads_user_add},
618 {"INFO", ads_user_info},
619 {"DELETE", ads_user_delete},
620 {NULL, NULL}
622 ADS_STRUCT *ads;
623 ADS_STATUS rc;
624 const char *shortattrs[] = {"sAMAccountName", NULL};
625 const char *longattrs[] = {"sAMAccountName", "description", NULL};
626 char *disp_fields[2] = {NULL, NULL};
628 if (argc == 0) {
629 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
630 return -1;
633 if (opt_long_list_entries)
634 d_printf("\nUser name Comment"\
635 "\n-----------------------------\n");
637 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
638 LDAP_SCOPE_SUBTREE,
639 "(objectCategory=user)",
640 opt_long_list_entries ? longattrs :
641 shortattrs, usergrp_display,
642 disp_fields);
643 ads_destroy(&ads);
644 return ADS_ERR_OK(rc) ? 0 : -1;
647 return net_run_function(argc, argv, func, net_ads_user_usage);
650 static int net_ads_group_usage(int argc, const char **argv)
652 return net_help_group(argc, argv);
655 static int ads_group_add(int argc, const char **argv)
657 ADS_STRUCT *ads;
658 ADS_STATUS status;
659 LDAPMessage *res=NULL;
660 int rc = -1;
661 char *ou_str = NULL;
663 if (argc < 1) {
664 return net_ads_group_usage(argc, argv);
667 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
668 return -1;
671 status = ads_find_user_acct(ads, &res, argv[0]);
673 if (!ADS_ERR_OK(status)) {
674 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
675 goto done;
678 if (ads_count_replies(ads, res)) {
679 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
680 goto done;
683 if (opt_container) {
684 ou_str = SMB_STRDUP(opt_container);
685 } else {
686 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
689 status = ads_add_group_acct(ads, argv[0], ou_str, opt_comment);
691 if (ADS_ERR_OK(status)) {
692 d_printf("Group %s added\n", argv[0]);
693 rc = 0;
694 } else {
695 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
696 ads_errstr(status));
699 done:
700 if (res)
701 ads_msgfree(ads, res);
702 ads_destroy(&ads);
703 SAFE_FREE(ou_str);
704 return rc;
707 static int ads_group_delete(int argc, const char **argv)
709 ADS_STRUCT *ads;
710 ADS_STATUS rc;
711 LDAPMessage *res = NULL;
712 char *groupdn;
714 if (argc < 1) {
715 return net_ads_group_usage(argc, argv);
718 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
719 return -1;
722 rc = ads_find_user_acct(ads, &res, argv[0]);
723 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
724 d_printf("Group %s does not exist.\n", argv[0]);
725 ads_msgfree(ads, res);
726 ads_destroy(&ads);
727 return -1;
729 groupdn = ads_get_dn(ads, res);
730 ads_msgfree(ads, res);
731 rc = ads_del_dn(ads, groupdn);
732 ads_memfree(ads, groupdn);
733 if (ADS_ERR_OK(rc)) {
734 d_printf("Group %s deleted\n", argv[0]);
735 ads_destroy(&ads);
736 return 0;
738 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
739 ads_errstr(rc));
740 ads_destroy(&ads);
741 return -1;
744 int net_ads_group(int argc, const char **argv)
746 struct functable func[] = {
747 {"ADD", ads_group_add},
748 {"DELETE", ads_group_delete},
749 {NULL, NULL}
751 ADS_STRUCT *ads;
752 ADS_STATUS rc;
753 const char *shortattrs[] = {"sAMAccountName", NULL};
754 const char *longattrs[] = {"sAMAccountName", "description", NULL};
755 char *disp_fields[2] = {NULL, NULL};
757 if (argc == 0) {
758 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
759 return -1;
762 if (opt_long_list_entries)
763 d_printf("\nGroup name Comment"\
764 "\n-----------------------------\n");
765 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
766 LDAP_SCOPE_SUBTREE,
767 "(objectCategory=group)",
768 opt_long_list_entries ? longattrs :
769 shortattrs, usergrp_display,
770 disp_fields);
772 ads_destroy(&ads);
773 return ADS_ERR_OK(rc) ? 0 : -1;
775 return net_run_function(argc, argv, func, net_ads_group_usage);
778 static int net_ads_status(int argc, const char **argv)
780 ADS_STRUCT *ads;
781 ADS_STATUS rc;
782 LDAPMessage *res;
784 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
785 return -1;
788 rc = ads_find_machine_acct(ads, &res, global_myname());
789 if (!ADS_ERR_OK(rc)) {
790 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
791 ads_destroy(&ads);
792 return -1;
795 if (ads_count_replies(ads, res) == 0) {
796 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
797 ads_destroy(&ads);
798 return -1;
801 ads_dump(ads, res);
802 ads_destroy(&ads);
803 return 0;
806 /*******************************************************************
807 Leave an AD domain. Windows XP disables the machine account.
808 We'll try the same. The old code would do an LDAP delete.
809 That only worked using the machine creds because added the machine
810 with full control to the computer object's ACL.
811 *******************************************************************/
813 static int net_ads_leave(int argc, const char **argv)
815 TALLOC_CTX *ctx;
816 struct libnet_UnjoinCtx *r = NULL;
817 WERROR werr;
819 if (!(ctx = talloc_init("net_ads_leave"))) {
820 d_fprintf(stderr, "Could not initialise talloc context.\n");
821 return -1;
824 use_in_memory_ccache();
826 werr = libnet_init_UnjoinCtx(ctx, &r);
827 if (!W_ERROR_IS_OK(werr)) {
828 d_fprintf(stderr, "Could not initialise unjoin context.\n");
829 return -1;
832 r->in.debug = opt_verbose;
833 r->in.dc_name = opt_host;
834 r->in.domain_name = lp_realm();
835 r->in.admin_account = opt_user_name;
836 r->in.admin_password = net_prompt_pass(opt_user_name);
837 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
838 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
840 werr = libnet_Unjoin(ctx, r);
841 if (!W_ERROR_IS_OK(werr)) {
842 d_printf("Failed to leave domain: %s\n",
843 r->out.error_string ? r->out.error_string :
844 get_friendly_werror_msg(werr));
845 goto done;
848 if (W_ERROR_IS_OK(werr)) {
849 d_printf("Deleted account for '%s' in realm '%s'\n",
850 r->in.machine_name, r->out.dns_domain_name);
851 goto done;
854 /* We couldn't delete it - see if the disable succeeded. */
855 if (r->out.disabled_machine_account) {
856 d_printf("Disabled account for '%s' in realm '%s'\n",
857 r->in.machine_name, r->out.dns_domain_name);
858 werr = WERR_OK;
859 goto done;
862 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
863 r->in.machine_name, r->out.dns_domain_name);
865 done:
866 TALLOC_FREE(r);
867 TALLOC_FREE(ctx);
869 if (W_ERROR_IS_OK(werr)) {
870 return 0;
873 return -1;
876 static NTSTATUS net_ads_join_ok(void)
878 ADS_STRUCT *ads = NULL;
879 ADS_STATUS status;
881 if (!secrets_init()) {
882 DEBUG(1,("Failed to initialise secrets database\n"));
883 return NT_STATUS_ACCESS_DENIED;
886 net_use_krb_machine_account();
888 status = ads_startup(True, &ads);
889 if (!ADS_ERR_OK(status)) {
890 return ads_ntstatus(status);
893 ads_destroy(&ads);
894 return NT_STATUS_OK;
898 check that an existing join is OK
900 int net_ads_testjoin(int argc, const char **argv)
902 NTSTATUS status;
903 use_in_memory_ccache();
905 /* Display success or failure */
906 status = net_ads_join_ok();
907 if (!NT_STATUS_IS_OK(status)) {
908 fprintf(stderr,"Join to domain is not valid: %s\n",
909 get_friendly_nt_error_msg(status));
910 return -1;
913 printf("Join is OK\n");
914 return 0;
917 /*******************************************************************
918 Simple configu checks before beginning the join
919 ********************************************************************/
921 static NTSTATUS check_ads_config( void )
923 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
924 d_printf("Host is not configured as a member server.\n");
925 return NT_STATUS_INVALID_DOMAIN_ROLE;
928 if (strlen(global_myname()) > 15) {
929 d_printf("Our netbios name can be at most 15 chars long, "
930 "\"%s\" is %u chars long\n", global_myname(),
931 (unsigned int)strlen(global_myname()));
932 return NT_STATUS_NAME_TOO_LONG;
935 if ( lp_security() == SEC_ADS && !*lp_realm()) {
936 d_fprintf(stderr, "realm must be set in in %s for ADS "
937 "join to succeed.\n", get_dyn_CONFIGFILE());
938 return NT_STATUS_INVALID_PARAMETER;
941 if (!secrets_init()) {
942 DEBUG(1,("Failed to initialise secrets database\n"));
943 /* This is a good bet for failure of secrets_init ... */
944 return NT_STATUS_ACCESS_DENIED;
947 return NT_STATUS_OK;
950 /*******************************************************************
951 Do the domain join
952 ********************************************************************/
954 static NTSTATUS net_join_domain(TALLOC_CTX *ctx, const char *servername,
955 struct sockaddr_storage *pss,
956 const char **domain,
957 DOM_SID **dom_sid,
958 const char *password)
960 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
961 struct cli_state *cli = NULL;
963 ret = connect_to_ipc_krb5(&cli, pss, servername);
964 if ( !NT_STATUS_IS_OK(ret) ) {
965 goto done;
968 ret = netdom_get_domain_sid( ctx, cli, domain, dom_sid );
969 if ( !NT_STATUS_IS_OK(ret) ) {
970 goto done;
973 /* cli->server_domain is not filled in when using krb5
974 session setups */
976 saf_store( *domain, cli->desthost );
978 ret = netdom_join_domain( ctx, cli, *dom_sid, password, ND_TYPE_AD );
980 done:
981 if ( cli )
982 cli_shutdown(cli);
984 return ret;
987 /*******************************************************************
988 Set a machines dNSHostName and servicePrincipalName attributes
989 ********************************************************************/
991 static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
993 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
994 char *new_dn;
995 ADS_MODLIST mods;
996 const char *servicePrincipalName[3] = {NULL, NULL, NULL};
997 char *psp;
998 fstring my_fqdn;
999 LDAPMessage *res = NULL;
1000 char *dn_string = NULL;
1001 const char *machine_name = global_myname();
1002 int count;
1004 if ( !machine_name ) {
1005 return ADS_ERROR(LDAP_NO_MEMORY);
1008 /* Find our DN */
1010 status = ads_find_machine_acct(ads_s, &res, machine_name);
1011 if (!ADS_ERR_OK(status))
1012 return status;
1014 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1015 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1016 return ADS_ERROR(LDAP_NO_MEMORY);
1019 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1020 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1021 goto done;
1024 new_dn = talloc_strdup(ctx, dn_string);
1025 ads_memfree(ads_s, dn_string);
1026 if (!new_dn) {
1027 return ADS_ERROR(LDAP_NO_MEMORY);
1030 /* Windows only creates HOST/shortname & HOST/fqdn. */
1032 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) )
1033 goto done;
1034 strupper_m(psp);
1035 servicePrincipalName[0] = psp;
1037 name_to_fqdn(my_fqdn, machine_name);
1038 strlower_m(my_fqdn);
1039 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) )
1040 goto done;
1041 servicePrincipalName[1] = psp;
1043 if (!(mods = ads_init_mods(ctx))) {
1044 goto done;
1047 /* fields of primary importance */
1049 ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
1050 ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
1052 status = ads_gen_mod(ads_s, new_dn, mods);
1054 done:
1055 ads_msgfree(ads_s, res);
1057 return status;
1060 /*******************************************************************
1061 Set a machines dNSHostName and servicePrincipalName attributes
1062 ********************************************************************/
1064 static ADS_STATUS net_set_machine_upn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, const char *upn )
1066 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1067 char *new_dn;
1068 ADS_MODLIST mods;
1069 LDAPMessage *res = NULL;
1070 char *dn_string = NULL;
1071 const char *machine_name = global_myname();
1072 int count;
1074 if ( !machine_name ) {
1075 return ADS_ERROR(LDAP_NO_MEMORY);
1078 /* Find our DN */
1080 status = ads_find_machine_acct(ads_s, &res, machine_name);
1081 if (!ADS_ERR_OK(status))
1082 return status;
1084 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1085 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1086 return ADS_ERROR(LDAP_NO_MEMORY);
1089 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1090 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1091 goto done;
1094 new_dn = talloc_strdup(ctx, dn_string);
1095 ads_memfree(ads_s, dn_string);
1096 if (!new_dn) {
1097 return ADS_ERROR(LDAP_NO_MEMORY);
1100 /* now do the mods */
1102 if (!(mods = ads_init_mods(ctx))) {
1103 goto done;
1106 /* fields of primary importance */
1108 ads_mod_str(ctx, &mods, "userPrincipalName", upn);
1110 status = ads_gen_mod(ads_s, new_dn, mods);
1112 done:
1113 ads_msgfree(ads_s, res);
1115 return status;
1118 /*******************************************************************
1119 Set a machines dNSHostName and servicePrincipalName attributes
1120 ********************************************************************/
1122 static ADS_STATUS net_set_os_attributes(TALLOC_CTX *ctx, ADS_STRUCT *ads_s,
1123 const char *os_name, const char *os_version )
1125 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1126 char *new_dn;
1127 ADS_MODLIST mods;
1128 LDAPMessage *res = NULL;
1129 char *dn_string = NULL;
1130 const char *machine_name = global_myname();
1131 int count;
1132 char *os_sp = NULL;
1134 if ( !os_name || !os_version ) {
1135 return ADS_ERROR(LDAP_NO_MEMORY);
1138 /* Find our DN */
1140 status = ads_find_machine_acct(ads_s, &res, machine_name);
1141 if (!ADS_ERR_OK(status))
1142 return status;
1144 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1145 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1146 return ADS_ERROR(LDAP_NO_MEMORY);
1149 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1150 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1151 goto done;
1154 new_dn = talloc_strdup(ctx, dn_string);
1155 ads_memfree(ads_s, dn_string);
1156 if (!new_dn) {
1157 return ADS_ERROR(LDAP_NO_MEMORY);
1160 /* now do the mods */
1162 if (!(mods = ads_init_mods(ctx))) {
1163 goto done;
1166 os_sp = talloc_asprintf( ctx, "Samba %s", SAMBA_VERSION_STRING );
1168 /* fields of primary importance */
1170 ads_mod_str(ctx, &mods, "operatingSystem", os_name);
1171 ads_mod_str(ctx, &mods, "operatingSystemVersion", os_version);
1172 if ( os_sp )
1173 ads_mod_str(ctx, &mods, "operatingSystemServicePack", os_sp);
1175 status = ads_gen_mod(ads_s, new_dn, mods);
1177 done:
1178 ads_msgfree(ads_s, res);
1179 TALLOC_FREE( os_sp );
1181 return status;
1184 /*******************************************************************
1185 join a domain using ADS (LDAP mods)
1186 ********************************************************************/
1188 static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
1190 ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
1191 char *ou_str = NULL;
1192 char *dn = NULL;
1193 LDAPMessage *res = NULL;
1194 bool moved;
1196 ou_str = ads_ou_string(ads, ou);
1197 if (asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path) == -1) {
1198 rc = ADS_ERROR(LDAP_NO_MEMORY);
1199 goto done;
1202 rc = ads_search_dn(ads, &res, dn, NULL);
1203 if (!ADS_ERR_OK(rc)) {
1204 d_fprintf(stderr, "The specified OU does not exist.\n");
1205 goto done;
1208 /* Attempt to create the machine account and bail if this fails.
1209 Assume that the admin wants exactly what they requested */
1211 rc = ads_create_machine_acct( ads, global_myname(), dn );
1212 if (ADS_ERR_OK(rc)) {
1213 DEBUG(1, ("machine account created\n"));
1214 goto done;
1216 if ( !(rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS) ) {
1217 DEBUG(1, ("machine account creation failed\n"));
1218 goto done;
1221 rc = ads_move_machine_acct(ads, global_myname(), dn, &moved);
1222 if (!ADS_ERR_OK(rc)) {
1223 DEBUG(1, ("failure to locate/move pre-existing machine account\n"));
1224 goto done;
1227 if (moved) {
1228 d_printf("The machine account was moved into the specified OU.\n");
1229 } else {
1230 d_printf("The machine account already exists in the specified OU.\n");
1233 done:
1234 ads_msgfree(ads, res);
1235 SAFE_FREE( ou_str );
1236 SAFE_FREE( dn );
1238 return rc;
1241 /************************************************************************
1242 ************************************************************************/
1244 static bool net_derive_salting_principal( TALLOC_CTX *ctx, ADS_STRUCT *ads )
1246 uint32 domain_func;
1247 ADS_STATUS status;
1248 fstring salt;
1249 char *std_salt;
1250 const char *machine_name = global_myname();
1252 status = ads_domain_func_level( ads, &domain_func );
1253 if ( !ADS_ERR_OK(status) ) {
1254 DEBUG(2,("Failed to determine domain functional level!\n"));
1255 return False;
1258 /* go ahead and setup the default salt */
1260 if ( (std_salt = kerberos_standard_des_salt()) == NULL ) {
1261 d_fprintf(stderr, "net_derive_salting_principal: failed to obtain stanard DES salt\n");
1262 return False;
1265 fstrcpy( salt, std_salt );
1266 SAFE_FREE( std_salt );
1268 /* if it's a Windows functional domain, we have to look for the UPN */
1270 if ( domain_func == DS_DOMAIN_FUNCTION_2000 ) {
1271 char *upn = ads_get_upn(ads, ctx, machine_name);
1272 if ( upn ) {
1273 fstrcpy( salt, upn );
1277 return kerberos_secrets_store_des_salt( salt );
1280 /*******************************************************************
1281 Send a DNS update request
1282 *******************************************************************/
1284 #if defined(WITH_DNS_UPDATES)
1285 #include "dns.h"
1286 DNS_ERROR DoDNSUpdate(char *pszServerName,
1287 const char *pszDomainName, const char *pszHostName,
1288 const struct sockaddr_storage *sslist,
1289 size_t num_addrs );
1291 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1292 const char *machine_name,
1293 const struct sockaddr_storage *addrs,
1294 int num_addrs)
1296 struct dns_rr_ns *nameservers = NULL;
1297 int ns_count = 0;
1298 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1299 DNS_ERROR dns_err;
1300 fstring dns_server;
1301 const char *dnsdomain = NULL;
1302 char *root_domain = NULL;
1304 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1305 d_printf("No DNS domain configured for %s. "
1306 "Unable to perform DNS Update.\n", machine_name);
1307 status = NT_STATUS_INVALID_PARAMETER;
1308 goto done;
1310 dnsdomain++;
1312 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1313 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1314 /* Child domains often do not have NS records. Look
1315 for the NS record for the forest root domain
1316 (rootDomainNamingContext in therootDSE) */
1318 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1319 LDAPMessage *msg = NULL;
1320 char *root_dn;
1321 ADS_STATUS ads_status;
1323 if ( !ads->ldap.ld ) {
1324 ads_status = ads_connect( ads );
1325 if ( !ADS_ERR_OK(ads_status) ) {
1326 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1327 goto done;
1331 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1332 "(objectclass=*)", rootname_attrs, &msg);
1333 if (!ADS_ERR_OK(ads_status)) {
1334 goto done;
1337 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1338 if ( !root_dn ) {
1339 ads_msgfree( ads, msg );
1340 goto done;
1343 root_domain = ads_build_domain( root_dn );
1345 /* cleanup */
1346 ads_msgfree( ads, msg );
1348 /* try again for NS servers */
1350 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1352 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1353 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1354 "realm\n", ads->config.realm));
1355 goto done;
1358 dnsdomain = root_domain;
1362 /* Now perform the dns update - we'll try non-secure and if we fail,
1363 we'll follow it up with a secure update */
1365 fstrcpy( dns_server, nameservers[0].hostname );
1367 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1368 if (!ERR_DNS_IS_OK(dns_err)) {
1369 status = NT_STATUS_UNSUCCESSFUL;
1372 done:
1374 SAFE_FREE( root_domain );
1376 return status;
1379 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1381 int num_addrs;
1382 struct sockaddr_storage *iplist = NULL;
1383 fstring machine_name;
1384 NTSTATUS status;
1386 name_to_fqdn( machine_name, global_myname() );
1387 strlower_m( machine_name );
1389 /* Get our ip address (not the 127.0.0.x address but a real ip
1390 * address) */
1392 num_addrs = get_my_ip_address( &iplist );
1393 if ( num_addrs <= 0 ) {
1394 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1395 "addresses!\n"));
1396 return NT_STATUS_INVALID_PARAMETER;
1399 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1400 iplist, num_addrs);
1401 SAFE_FREE( iplist );
1402 return status;
1404 #endif
1407 /*******************************************************************
1408 ********************************************************************/
1410 static int net_ads_join_usage(int argc, const char **argv)
1412 d_printf("net ads join [options]\n");
1413 d_printf("Valid options:\n");
1414 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1415 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1416 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1417 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1418 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1419 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1420 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1421 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1422 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1423 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1424 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1425 d_printf(" the two other attributes.\n");
1427 return -1;
1430 /*******************************************************************
1431 ********************************************************************/
1433 int net_ads_join(int argc, const char **argv)
1435 NTSTATUS nt_status;
1436 TALLOC_CTX *ctx = NULL;
1437 struct libnet_JoinCtx *r = NULL;
1438 const char *domain = lp_realm();
1439 WERROR werr = WERR_SETUP_NOT_JOINED;
1440 bool createupn = False;
1441 const char *machineupn = NULL;
1442 const char *create_in_ou = NULL;
1443 int i;
1444 const char *os_name = NULL;
1445 const char *os_version = NULL;
1447 nt_status = check_ads_config();
1448 if (!NT_STATUS_IS_OK(nt_status)) {
1449 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1450 werr = ntstatus_to_werror(nt_status);
1451 goto fail;
1454 use_in_memory_ccache();
1456 werr = libnet_init_JoinCtx(ctx, &r);
1457 if (!W_ERROR_IS_OK(werr)) {
1458 goto fail;
1461 if (!(ctx = talloc_init("net_ads_join"))) {
1462 d_fprintf(stderr, "Could not initialise talloc context.\n");
1463 werr = WERR_NOMEM;
1464 goto fail;
1467 /* process additional command line args */
1469 for ( i=0; i<argc; i++ ) {
1470 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1471 createupn = True;
1472 machineupn = get_string_param(argv[i]);
1474 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1475 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1476 d_fprintf(stderr, "Please supply a valid OU path.\n");
1477 werr = WERR_INVALID_PARAM;
1478 goto fail;
1481 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1482 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1483 d_fprintf(stderr, "Please supply a operating system name.\n");
1484 werr = WERR_INVALID_PARAM;
1485 goto fail;
1488 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1489 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1490 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1491 werr = WERR_INVALID_PARAM;
1492 goto fail;
1495 else {
1496 domain = argv[i];
1500 /* Do the domain join here */
1502 r->in.domain_name = domain;
1503 r->in.create_upn = createupn;
1504 r->in.upn = machineupn;
1505 r->in.account_ou = create_in_ou;
1506 r->in.os_name = os_name;
1507 r->in.os_version = os_version;
1508 r->in.dc_name = opt_host;
1509 r->in.admin_account = opt_user_name;
1510 r->in.admin_password = net_prompt_pass(opt_user_name);
1511 r->in.debug = opt_verbose;
1512 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1513 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1514 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1516 werr = libnet_Join(ctx, r);
1517 if (!W_ERROR_IS_OK(werr)) {
1518 goto fail;
1521 /* Check the short name of the domain */
1523 if (!strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1524 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1525 d_printf("domain name obtained from the server.\n");
1526 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1527 d_printf("You should set \"workgroup = %s\" in %s.\n",
1528 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1531 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1533 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1534 r->out.dns_domain_name);
1536 #if defined(WITH_DNS_UPDATES)
1538 /* We enter this block with user creds */
1539 ADS_STRUCT *ads_dns = NULL;
1541 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1542 /* kinit with the machine password */
1544 use_in_memory_ccache();
1545 asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1546 ads_dns->auth.password = secrets_fetch_machine_password(
1547 lp_workgroup(), NULL, NULL );
1548 ads_dns->auth.realm = SMB_STRDUP( lp_realm() );
1549 ads_kinit_password( ads_dns );
1552 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1553 d_fprintf( stderr, "DNS update failed!\n" );
1556 /* exit from this block using machine creds */
1557 ads_destroy(&ads_dns);
1559 #endif
1560 TALLOC_FREE(r);
1561 TALLOC_FREE( ctx );
1563 return 0;
1565 fail:
1566 /* issue an overall failure message at the end. */
1567 d_printf("Failed to join domain: %s\n",
1568 r && r->out.error_string ? r->out.error_string :
1569 get_friendly_werror_msg(werr));
1570 TALLOC_FREE( ctx );
1572 return -1;
1575 /*******************************************************************
1576 ********************************************************************/
1578 static int net_ads_dns_usage(int argc, const char **argv)
1580 #if defined(WITH_DNS_UPDATES)
1581 d_printf("net ads dns <command>\n");
1582 d_printf("Valid commands:\n");
1583 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1585 return 0;
1586 #else
1587 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1588 return -1;
1589 #endif
1592 /*******************************************************************
1593 ********************************************************************/
1595 static int net_ads_dns_register(int argc, const char **argv)
1597 #if defined(WITH_DNS_UPDATES)
1598 ADS_STRUCT *ads;
1599 ADS_STATUS status;
1600 TALLOC_CTX *ctx;
1602 #ifdef DEVELOPER
1603 talloc_enable_leak_report();
1604 #endif
1606 if (argc > 0) {
1607 d_fprintf(stderr, "net ads dns register\n");
1608 return -1;
1611 if (!(ctx = talloc_init("net_ads_dns"))) {
1612 d_fprintf(stderr, "Could not initialise talloc context\n");
1613 return -1;
1616 status = ads_startup(True, &ads);
1617 if ( !ADS_ERR_OK(status) ) {
1618 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1619 TALLOC_FREE(ctx);
1620 return -1;
1623 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1624 d_fprintf( stderr, "DNS update failed!\n" );
1625 ads_destroy( &ads );
1626 TALLOC_FREE( ctx );
1627 return -1;
1630 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1632 ads_destroy(&ads);
1633 TALLOC_FREE( ctx );
1635 return 0;
1636 #else
1637 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1638 return -1;
1639 #endif
1642 #if defined(WITH_DNS_UPDATES)
1643 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1644 #endif
1646 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1648 #if defined(WITH_DNS_UPDATES)
1649 DNS_ERROR err;
1651 #ifdef DEVELOPER
1652 talloc_enable_leak_report();
1653 #endif
1655 if (argc != 2) {
1656 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1657 "<name>\n");
1658 return -1;
1661 err = do_gethostbyname(argv[0], argv[1]);
1663 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1664 #endif
1665 return 0;
1668 static int net_ads_dns(int argc, const char *argv[])
1670 struct functable func[] = {
1671 {"REGISTER", net_ads_dns_register},
1672 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1673 {NULL, NULL}
1676 return net_run_function(argc, argv, func, net_ads_dns_usage);
1679 /*******************************************************************
1680 ********************************************************************/
1682 int net_ads_printer_usage(int argc, const char **argv)
1684 d_printf(
1685 "\nnet ads printer search <printer>"
1686 "\n\tsearch for a printer in the directory\n"
1687 "\nnet ads printer info <printer> <server>"
1688 "\n\tlookup info in directory for printer on server"
1689 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1690 "\nnet ads printer publish <printername>"
1691 "\n\tpublish printer in directory"
1692 "\n\t(note: printer name is required)\n"
1693 "\nnet ads printer remove <printername>"
1694 "\n\tremove printer from directory"
1695 "\n\t(note: printer name is required)\n");
1696 return -1;
1699 /*******************************************************************
1700 ********************************************************************/
1702 static int net_ads_printer_search(int argc, const char **argv)
1704 ADS_STRUCT *ads;
1705 ADS_STATUS rc;
1706 LDAPMessage *res = NULL;
1708 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1709 return -1;
1712 rc = ads_find_printers(ads, &res);
1714 if (!ADS_ERR_OK(rc)) {
1715 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1716 ads_msgfree(ads, res);
1717 ads_destroy(&ads);
1718 return -1;
1721 if (ads_count_replies(ads, res) == 0) {
1722 d_fprintf(stderr, "No results found\n");
1723 ads_msgfree(ads, res);
1724 ads_destroy(&ads);
1725 return -1;
1728 ads_dump(ads, res);
1729 ads_msgfree(ads, res);
1730 ads_destroy(&ads);
1731 return 0;
1734 static int net_ads_printer_info(int argc, const char **argv)
1736 ADS_STRUCT *ads;
1737 ADS_STATUS rc;
1738 const char *servername, *printername;
1739 LDAPMessage *res = NULL;
1741 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1742 return -1;
1745 if (argc > 0) {
1746 printername = argv[0];
1747 } else {
1748 printername = "*";
1751 if (argc > 1) {
1752 servername = argv[1];
1753 } else {
1754 servername = global_myname();
1757 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1759 if (!ADS_ERR_OK(rc)) {
1760 d_fprintf(stderr, "Server '%s' not found: %s\n",
1761 servername, ads_errstr(rc));
1762 ads_msgfree(ads, res);
1763 ads_destroy(&ads);
1764 return -1;
1767 if (ads_count_replies(ads, res) == 0) {
1768 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1769 ads_msgfree(ads, res);
1770 ads_destroy(&ads);
1771 return -1;
1774 ads_dump(ads, res);
1775 ads_msgfree(ads, res);
1776 ads_destroy(&ads);
1778 return 0;
1781 static int net_ads_printer_publish(int argc, const char **argv)
1783 ADS_STRUCT *ads;
1784 ADS_STATUS rc;
1785 const char *servername, *printername;
1786 struct cli_state *cli;
1787 struct rpc_pipe_client *pipe_hnd;
1788 struct sockaddr_storage server_ss;
1789 NTSTATUS nt_status;
1790 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1791 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1792 char *prt_dn, *srv_dn, **srv_cn;
1793 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1794 LDAPMessage *res = NULL;
1796 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1797 talloc_destroy(mem_ctx);
1798 return -1;
1801 if (argc < 1) {
1802 talloc_destroy(mem_ctx);
1803 return net_ads_printer_usage(argc, argv);
1806 printername = argv[0];
1808 if (argc == 2) {
1809 servername = argv[1];
1810 } else {
1811 servername = global_myname();
1814 /* Get printer data from SPOOLSS */
1816 resolve_name(servername, &server_ss, 0x20);
1818 nt_status = cli_full_connection(&cli, global_myname(), servername,
1819 &server_ss, 0,
1820 "IPC$", "IPC",
1821 opt_user_name, opt_workgroup,
1822 opt_password ? opt_password : "",
1823 CLI_FULL_CONNECTION_USE_KERBEROS,
1824 Undefined, NULL);
1826 if (NT_STATUS_IS_ERR(nt_status)) {
1827 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1828 "for %s\n", servername, printername);
1829 ads_destroy(&ads);
1830 talloc_destroy(mem_ctx);
1831 return -1;
1834 /* Publish on AD server */
1836 ads_find_machine_acct(ads, &res, servername);
1838 if (ads_count_replies(ads, res) == 0) {
1839 d_fprintf(stderr, "Could not find machine account for server %s\n",
1840 servername);
1841 ads_destroy(&ads);
1842 talloc_destroy(mem_ctx);
1843 return -1;
1846 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1847 srv_cn = ldap_explode_dn(srv_dn, 1);
1849 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1850 printername_escaped = escape_rdn_val_string_alloc(printername);
1851 if (!srv_cn_escaped || !printername_escaped) {
1852 SAFE_FREE(srv_cn_escaped);
1853 SAFE_FREE(printername_escaped);
1854 d_fprintf(stderr, "Internal error, out of memory!");
1855 ads_destroy(&ads);
1856 talloc_destroy(mem_ctx);
1857 return -1;
1860 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1862 SAFE_FREE(srv_cn_escaped);
1863 SAFE_FREE(printername_escaped);
1865 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1866 if (!pipe_hnd) {
1867 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1868 servername);
1869 SAFE_FREE(prt_dn);
1870 ads_destroy(&ads);
1871 talloc_destroy(mem_ctx);
1872 return -1;
1875 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1876 printername))) {
1877 SAFE_FREE(prt_dn);
1878 ads_destroy(&ads);
1879 talloc_destroy(mem_ctx);
1880 return -1;
1883 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1884 if (!ADS_ERR_OK(rc)) {
1885 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1886 SAFE_FREE(prt_dn);
1887 ads_destroy(&ads);
1888 talloc_destroy(mem_ctx);
1889 return -1;
1892 d_printf("published printer\n");
1893 SAFE_FREE(prt_dn);
1894 ads_destroy(&ads);
1895 talloc_destroy(mem_ctx);
1897 return 0;
1900 static int net_ads_printer_remove(int argc, const char **argv)
1902 ADS_STRUCT *ads;
1903 ADS_STATUS rc;
1904 const char *servername;
1905 char *prt_dn;
1906 LDAPMessage *res = NULL;
1908 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1909 return -1;
1912 if (argc < 1) {
1913 return net_ads_printer_usage(argc, argv);
1916 if (argc > 1) {
1917 servername = argv[1];
1918 } else {
1919 servername = global_myname();
1922 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1924 if (!ADS_ERR_OK(rc)) {
1925 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1926 ads_msgfree(ads, res);
1927 ads_destroy(&ads);
1928 return -1;
1931 if (ads_count_replies(ads, res) == 0) {
1932 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1933 ads_msgfree(ads, res);
1934 ads_destroy(&ads);
1935 return -1;
1938 prt_dn = ads_get_dn(ads, res);
1939 ads_msgfree(ads, res);
1940 rc = ads_del_dn(ads, prt_dn);
1941 ads_memfree(ads, prt_dn);
1943 if (!ADS_ERR_OK(rc)) {
1944 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1945 ads_destroy(&ads);
1946 return -1;
1949 ads_destroy(&ads);
1950 return 0;
1953 static int net_ads_printer(int argc, const char **argv)
1955 struct functable func[] = {
1956 {"SEARCH", net_ads_printer_search},
1957 {"INFO", net_ads_printer_info},
1958 {"PUBLISH", net_ads_printer_publish},
1959 {"REMOVE", net_ads_printer_remove},
1960 {NULL, NULL}
1963 return net_run_function(argc, argv, func, net_ads_printer_usage);
1967 static int net_ads_password(int argc, const char **argv)
1969 ADS_STRUCT *ads;
1970 const char *auth_principal = opt_user_name;
1971 const char *auth_password = opt_password;
1972 char *realm = NULL;
1973 char *new_password = NULL;
1974 char *c, *prompt;
1975 const char *user;
1976 ADS_STATUS ret;
1978 if (opt_user_name == NULL || opt_password == NULL) {
1979 d_fprintf(stderr, "You must supply an administrator username/password\n");
1980 return -1;
1983 if (argc < 1) {
1984 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1985 return -1;
1988 user = argv[0];
1989 if (!strchr_m(user, '@')) {
1990 asprintf(&c, "%s@%s", argv[0], lp_realm());
1991 user = c;
1994 use_in_memory_ccache();
1995 c = strchr_m(auth_principal, '@');
1996 if (c) {
1997 realm = ++c;
1998 } else {
1999 realm = lp_realm();
2002 /* use the realm so we can eventually change passwords for users
2003 in realms other than default */
2004 if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
2005 return -1;
2008 /* we don't actually need a full connect, but it's the easy way to
2009 fill in the KDC's addresss */
2010 ads_connect(ads);
2012 if (!ads || !ads->config.realm) {
2013 d_fprintf(stderr, "Didn't find the kerberos server!\n");
2014 return -1;
2017 if (argv[1]) {
2018 new_password = (char *)argv[1];
2019 } else {
2020 asprintf(&prompt, "Enter new password for %s:", user);
2021 new_password = getpass(prompt);
2022 free(prompt);
2025 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2026 auth_password, user, new_password, ads->auth.time_offset);
2027 if (!ADS_ERR_OK(ret)) {
2028 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
2029 ads_destroy(&ads);
2030 return -1;
2033 d_printf("Password change for %s completed.\n", user);
2034 ads_destroy(&ads);
2036 return 0;
2039 int net_ads_changetrustpw(int argc, const char **argv)
2041 ADS_STRUCT *ads;
2042 char *host_principal;
2043 fstring my_name;
2044 ADS_STATUS ret;
2046 if (!secrets_init()) {
2047 DEBUG(1,("Failed to initialise secrets database\n"));
2048 return -1;
2051 net_use_krb_machine_account();
2053 use_in_memory_ccache();
2055 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2056 return -1;
2059 fstrcpy(my_name, global_myname());
2060 strlower_m(my_name);
2061 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
2062 d_printf("Changing password for principal: %s\n", host_principal);
2064 ret = ads_change_trust_account_password(ads, host_principal);
2066 if (!ADS_ERR_OK(ret)) {
2067 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
2068 ads_destroy(&ads);
2069 SAFE_FREE(host_principal);
2070 return -1;
2073 d_printf("Password change for principal %s succeeded.\n", host_principal);
2075 if (lp_use_kerberos_keytab()) {
2076 d_printf("Attempting to update system keytab with new password.\n");
2077 if (ads_keytab_create_default(ads)) {
2078 d_printf("Failed to update system keytab.\n");
2082 ads_destroy(&ads);
2083 SAFE_FREE(host_principal);
2085 return 0;
2089 help for net ads search
2091 static int net_ads_search_usage(int argc, const char **argv)
2093 d_printf(
2094 "\nnet ads search <expression> <attributes...>\n"\
2095 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2096 "The expression is a standard LDAP search expression, and the\n"\
2097 "attributes are a list of LDAP fields to show in the results\n\n"\
2098 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2100 net_common_flags_usage(argc, argv);
2101 return -1;
2106 general ADS search function. Useful in diagnosing problems in ADS
2108 static int net_ads_search(int argc, const char **argv)
2110 ADS_STRUCT *ads;
2111 ADS_STATUS rc;
2112 const char *ldap_exp;
2113 const char **attrs;
2114 LDAPMessage *res = NULL;
2116 if (argc < 1) {
2117 return net_ads_search_usage(argc, argv);
2120 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2121 return -1;
2124 ldap_exp = argv[0];
2125 attrs = (argv + 1);
2127 rc = ads_do_search_all(ads, ads->config.bind_path,
2128 LDAP_SCOPE_SUBTREE,
2129 ldap_exp, attrs, &res);
2130 if (!ADS_ERR_OK(rc)) {
2131 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2132 ads_destroy(&ads);
2133 return -1;
2136 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2138 /* dump the results */
2139 ads_dump(ads, res);
2141 ads_msgfree(ads, res);
2142 ads_destroy(&ads);
2144 return 0;
2149 help for net ads search
2151 static int net_ads_dn_usage(int argc, const char **argv)
2153 d_printf(
2154 "\nnet ads dn <dn> <attributes...>\n"\
2155 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2156 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
2157 "to show in the results\n\n"\
2158 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2159 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2161 net_common_flags_usage(argc, argv);
2162 return -1;
2167 general ADS search function. Useful in diagnosing problems in ADS
2169 static int net_ads_dn(int argc, const char **argv)
2171 ADS_STRUCT *ads;
2172 ADS_STATUS rc;
2173 const char *dn;
2174 const char **attrs;
2175 LDAPMessage *res = NULL;
2177 if (argc < 1) {
2178 return net_ads_dn_usage(argc, argv);
2181 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2182 return -1;
2185 dn = argv[0];
2186 attrs = (argv + 1);
2188 rc = ads_do_search_all(ads, dn,
2189 LDAP_SCOPE_BASE,
2190 "(objectclass=*)", attrs, &res);
2191 if (!ADS_ERR_OK(rc)) {
2192 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2193 ads_destroy(&ads);
2194 return -1;
2197 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2199 /* dump the results */
2200 ads_dump(ads, res);
2202 ads_msgfree(ads, res);
2203 ads_destroy(&ads);
2205 return 0;
2209 help for net ads sid search
2211 static int net_ads_sid_usage(int argc, const char **argv)
2213 d_printf(
2214 "\nnet ads sid <sid> <attributes...>\n"\
2215 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2216 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
2217 "to show in the results\n\n"\
2218 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2220 net_common_flags_usage(argc, argv);
2221 return -1;
2226 general ADS search function. Useful in diagnosing problems in ADS
2228 static int net_ads_sid(int argc, const char **argv)
2230 ADS_STRUCT *ads;
2231 ADS_STATUS rc;
2232 const char *sid_string;
2233 const char **attrs;
2234 LDAPMessage *res = NULL;
2235 DOM_SID sid;
2237 if (argc < 1) {
2238 return net_ads_sid_usage(argc, argv);
2241 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2242 return -1;
2245 sid_string = argv[0];
2246 attrs = (argv + 1);
2248 if (!string_to_sid(&sid, sid_string)) {
2249 d_fprintf(stderr, "could not convert sid\n");
2250 ads_destroy(&ads);
2251 return -1;
2254 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2255 if (!ADS_ERR_OK(rc)) {
2256 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2257 ads_destroy(&ads);
2258 return -1;
2261 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2263 /* dump the results */
2264 ads_dump(ads, res);
2266 ads_msgfree(ads, res);
2267 ads_destroy(&ads);
2269 return 0;
2273 static int net_ads_keytab_usage(int argc, const char **argv)
2275 d_printf(
2276 "net ads keytab <COMMAND>\n"\
2277 "<COMMAND> can be either:\n"\
2278 " ADD Adds new service principal\n"\
2279 " CREATE Creates a fresh keytab\n"\
2280 " FLUSH Flushes out all keytab entries\n"\
2281 " HELP Prints this help message\n"\
2282 " LIST List the keytab\n"\
2283 "The ADD and LIST command will take arguments, the other commands\n"\
2284 "will not take any arguments. The arguments given to ADD\n"\
2285 "should be a list of principals to add. For example, \n"\
2286 " net ads keytab add srv1 srv2\n"\
2287 "will add principals for the services srv1 and srv2 to the\n"\
2288 "system's keytab.\n"\
2289 "The LIST command takes a keytabname.\n"\
2290 "\n"
2292 return -1;
2295 static int net_ads_keytab_flush(int argc, const char **argv)
2297 int ret;
2298 ADS_STRUCT *ads;
2300 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2301 return -1;
2303 ret = ads_keytab_flush(ads);
2304 ads_destroy(&ads);
2305 return ret;
2308 static int net_ads_keytab_add(int argc, const char **argv)
2310 int i;
2311 int ret = 0;
2312 ADS_STRUCT *ads;
2314 d_printf("Processing principals to add...\n");
2315 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2316 return -1;
2318 for (i = 0; i < argc; i++) {
2319 ret |= ads_keytab_add_entry(ads, argv[i]);
2321 ads_destroy(&ads);
2322 return ret;
2325 static int net_ads_keytab_create(int argc, const char **argv)
2327 ADS_STRUCT *ads;
2328 int ret;
2330 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2331 return -1;
2333 ret = ads_keytab_create_default(ads);
2334 ads_destroy(&ads);
2335 return ret;
2338 static int net_ads_keytab_list(int argc, const char **argv)
2340 const char *keytab = NULL;
2342 if (argc >= 1) {
2343 keytab = argv[0];
2346 return ads_keytab_list(keytab);
2350 int net_ads_keytab(int argc, const char **argv)
2352 struct functable func[] = {
2353 {"ADD", net_ads_keytab_add},
2354 {"CREATE", net_ads_keytab_create},
2355 {"FLUSH", net_ads_keytab_flush},
2356 {"HELP", net_ads_keytab_usage},
2357 {"LIST", net_ads_keytab_list},
2358 {NULL, NULL}
2361 if (!lp_use_kerberos_keytab()) {
2362 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2363 use keytab functions.\n");
2366 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2369 static int net_ads_kerberos_usage(int argc, const char **argv)
2371 d_printf(
2372 "net ads kerberos <COMMAND>\n"\
2373 "<COMMAND> can be either:\n"\
2374 " RENEW Renew TGT from existing credential cache\n"\
2375 " PAC Dumps the Kerberos PAC\n"\
2376 " KINIT Retrieve Ticket Granting Ticket (TGT)\n"\
2377 "\n"
2380 return -1;
2383 static int net_ads_kerberos_renew(int argc, const char **argv)
2385 int ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2386 if (ret) {
2387 d_printf("failed to renew kerberos ticket: %s\n",
2388 error_message(ret));
2390 return ret;
2393 static int net_ads_kerberos_pac(int argc, const char **argv)
2395 struct PAC_DATA *pac = NULL;
2396 struct PAC_LOGON_INFO *info = NULL;
2397 TALLOC_CTX *mem_ctx = NULL;
2398 NTSTATUS status;
2399 int ret = -1;
2401 mem_ctx = talloc_init("net_ads_kerberos_pac");
2402 if (!mem_ctx) {
2403 goto out;
2406 opt_password = net_prompt_pass(opt_user_name);
2408 status = kerberos_return_pac(mem_ctx,
2409 opt_user_name,
2410 opt_password,
2412 NULL,
2413 NULL,
2414 NULL,
2415 True,
2416 True,
2417 2592000, /* one month */
2418 &pac);
2419 if (!NT_STATUS_IS_OK(status)) {
2420 d_printf("failed to query kerberos PAC: %s\n",
2421 nt_errstr(status));
2422 goto out;
2425 info = get_logon_info_from_pac(pac);
2426 if (info) {
2427 const char *s;
2428 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2429 d_printf("The Pac: %s\n", s);
2432 ret = 0;
2433 out:
2434 TALLOC_FREE(mem_ctx);
2435 return ret;
2438 static int net_ads_kerberos_kinit(int argc, const char **argv)
2440 TALLOC_CTX *mem_ctx = NULL;
2441 int ret = -1;
2442 NTSTATUS status;
2444 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2445 if (!mem_ctx) {
2446 goto out;
2449 opt_password = net_prompt_pass(opt_user_name);
2451 ret = kerberos_kinit_password_ext(opt_user_name,
2452 opt_password,
2454 NULL,
2455 NULL,
2456 NULL,
2457 True,
2458 True,
2459 2592000, /* one month */
2460 &status);
2461 if (ret) {
2462 d_printf("failed to kinit password: %s\n",
2463 nt_errstr(status));
2465 out:
2466 return ret;
2469 int net_ads_kerberos(int argc, const char **argv)
2471 struct functable func[] = {
2472 {"KINIT", net_ads_kerberos_kinit},
2473 {"RENEW", net_ads_kerberos_renew},
2474 {"PAC", net_ads_kerberos_pac},
2475 {"HELP", net_ads_kerberos_usage},
2476 {NULL, NULL}
2479 return net_run_function(argc, argv, func, net_ads_kerberos_usage);
2483 int net_ads_help(int argc, const char **argv)
2485 struct functable func[] = {
2486 {"USER", net_ads_user_usage},
2487 {"GROUP", net_ads_group_usage},
2488 {"PRINTER", net_ads_printer_usage},
2489 {"SEARCH", net_ads_search_usage},
2490 {"INFO", net_ads_info},
2491 {"JOIN", net_ads_join_usage},
2492 {"DNS", net_ads_dns_usage},
2493 {"LEAVE", net_ads_leave},
2494 {"STATUS", net_ads_status},
2495 {"PASSWORD", net_ads_password},
2496 {"CHANGETRUSTPW", net_ads_changetrustpw},
2497 {NULL, NULL}
2500 return net_run_function(argc, argv, func, net_ads_usage);
2503 int net_ads(int argc, const char **argv)
2505 struct functable func[] = {
2506 {"INFO", net_ads_info},
2507 {"JOIN", net_ads_join},
2508 {"TESTJOIN", net_ads_testjoin},
2509 {"LEAVE", net_ads_leave},
2510 {"STATUS", net_ads_status},
2511 {"USER", net_ads_user},
2512 {"GROUP", net_ads_group},
2513 {"DNS", net_ads_dns},
2514 {"PASSWORD", net_ads_password},
2515 {"CHANGETRUSTPW", net_ads_changetrustpw},
2516 {"PRINTER", net_ads_printer},
2517 {"SEARCH", net_ads_search},
2518 {"DN", net_ads_dn},
2519 {"SID", net_ads_sid},
2520 {"WORKGROUP", net_ads_workgroup},
2521 {"LOOKUP", net_ads_lookup},
2522 {"KEYTAB", net_ads_keytab},
2523 {"GPO", net_ads_gpo},
2524 {"KERBEROS", net_ads_kerberos},
2525 {"HELP", net_ads_help},
2526 {NULL, NULL}
2529 return net_run_function(argc, argv, func, net_ads_usage);
2532 #else
2534 static int net_ads_noads(void)
2536 d_fprintf(stderr, "ADS support not compiled in\n");
2537 return -1;
2540 int net_ads_keytab(int argc, const char **argv)
2542 return net_ads_noads();
2545 int net_ads_kerberos(int argc, const char **argv)
2547 return net_ads_noads();
2550 int net_ads_usage(int argc, const char **argv)
2552 return net_ads_noads();
2555 int net_ads_help(int argc, const char **argv)
2557 return net_ads_noads();
2560 int net_ads_changetrustpw(int argc, const char **argv)
2562 return net_ads_noads();
2565 int net_ads_join(int argc, const char **argv)
2567 return net_ads_noads();
2570 int net_ads_user(int argc, const char **argv)
2572 return net_ads_noads();
2575 int net_ads_group(int argc, const char **argv)
2577 return net_ads_noads();
2580 /* this one shouldn't display a message */
2581 int net_ads_check(void)
2583 return -1;
2586 int net_ads_check_our_domain(void)
2588 return -1;
2591 int net_ads(int argc, const char **argv)
2593 return net_ads_usage(argc, argv);
2596 #endif /* WITH_ADS */