Remove some statics
[Samba.git] / source / utils / net_ads.c
blobac8f79435492817603727a4b72b350314c725b52
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 #ifdef HAVE_ADS
28 int net_ads_usage(int argc, const char **argv)
30 d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
31 d_printf(" Join the local machine to a ADS realm\n");
32 d_printf("leave\n");
33 d_printf(" Remove the local machine from a ADS realm\n");
34 d_printf("testjoin\n");
35 d_printf(" Validates the machine account in the domain\n");
36 d_printf("user\n");
37 d_printf(" List, add, or delete users in the realm\n");
38 d_printf("group\n");
39 d_printf(" List, add, or delete groups in the realm\n");
40 d_printf("info\n");
41 d_printf(" Displays details regarding a specific AD server\n");
42 d_printf("status\n");
43 d_printf(" Display details regarding the machine's account in AD\n");
44 d_printf("lookup\n");
45 d_printf(" Performs CLDAP query of AD domain controllers\n");
46 d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
47 d_printf(" Change a user's password using an admin account\n");
48 d_printf(" (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
49 d_printf("changetrustpw\n");
50 d_printf(" Change the trust account password of this machine in the AD tree\n");
51 d_printf("printer [info | publish | remove] <printername> <servername>\n");
52 d_printf(" Lookup, add, or remove directory entry for a printer\n");
53 d_printf("{search,dn,sid}\n");
54 d_printf(" Issue LDAP search queries using a general filter, by DN, or by SID\n");
55 d_printf("keytab\n");
56 d_printf(" Manage a local keytab file based on the machine account in AD\n");
57 d_printf("dns\n");
58 d_printf(" Issue a dynamic DNS update request the server's hostname\n");
59 d_printf(" (using the machine credentials)\n");
61 return -1;
64 /* when we do not have sufficient input parameters to contact a remote domain
65 * we always fall back to our own realm - Guenther*/
67 static const char *assume_own_realm(void)
69 if (!opt_host && strequal(lp_workgroup(), opt_target_workgroup)) {
70 return lp_realm();
73 return NULL;
77 do a cldap netlogon query
79 static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
81 char addr[INET6_ADDRSTRLEN];
82 struct cldap_netlogon_reply reply;
83 struct GUID tmp_guid;
85 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
86 if ( !ads_cldap_netlogon(addr, ads->server.realm, &reply ) ) {
87 d_fprintf(stderr, "CLDAP query failed!\n");
88 return -1;
91 d_printf("Information for Domain Controller: %s\n\n",
92 addr);
94 d_printf("Response Type: ");
95 switch (reply.type) {
96 case SAMLOGON_AD_UNK_R:
97 d_printf("SAMLOGON\n");
98 break;
99 case SAMLOGON_AD_R:
100 d_printf("SAMLOGON_USER\n");
101 break;
102 default:
103 d_printf("0x%x\n", reply.type);
104 break;
107 smb_uuid_unpack(reply.guid, &tmp_guid);
108 d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), tmp_guid));
110 d_printf("Flags:\n"
111 "\tIs a PDC: %s\n"
112 "\tIs a GC of the forest: %s\n"
113 "\tIs an LDAP server: %s\n"
114 "\tSupports DS: %s\n"
115 "\tIs running a KDC: %s\n"
116 "\tIs running time services: %s\n"
117 "\tIs the closest DC: %s\n"
118 "\tIs writable: %s\n"
119 "\tHas a hardware clock: %s\n"
120 "\tIs a non-domain NC serviced by LDAP server: %s\n",
121 (reply.flags & ADS_PDC) ? "yes" : "no",
122 (reply.flags & ADS_GC) ? "yes" : "no",
123 (reply.flags & ADS_LDAP) ? "yes" : "no",
124 (reply.flags & ADS_DS) ? "yes" : "no",
125 (reply.flags & ADS_KDC) ? "yes" : "no",
126 (reply.flags & ADS_TIMESERV) ? "yes" : "no",
127 (reply.flags & ADS_CLOSEST) ? "yes" : "no",
128 (reply.flags & ADS_WRITABLE) ? "yes" : "no",
129 (reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
130 (reply.flags & ADS_NDNC) ? "yes" : "no");
132 printf("Forest:\t\t\t%s\n", reply.forest);
133 printf("Domain:\t\t\t%s\n", reply.domain);
134 printf("Domain Controller:\t%s\n", reply.hostname);
136 printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
137 printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
139 if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
140 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
142 printf("Server Site Name :\t\t%s\n", reply.server_site_name);
143 printf("Client Site Name :\t\t%s\n", reply.client_site_name);
145 d_printf("NT Version: %d\n", reply.version);
146 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
147 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
149 return 0;
153 this implements the CLDAP based netlogon lookup requests
154 for finding the domain controller of a ADS domain
156 static int net_ads_lookup(int argc, const char **argv)
158 ADS_STRUCT *ads;
160 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
161 d_fprintf(stderr, "Didn't find the cldap server!\n");
162 return -1;
165 if (!ads->config.realm) {
166 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
167 ads->ldap.port = 389;
170 return net_ads_cldap_netlogon(ads);
175 static int net_ads_info(int argc, const char **argv)
177 ADS_STRUCT *ads;
178 char addr[INET6_ADDRSTRLEN];
180 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
181 d_fprintf(stderr, "Didn't find the ldap server!\n");
182 return -1;
185 if (!ads || !ads->config.realm) {
186 d_fprintf(stderr, "Didn't find the ldap server!\n");
187 return -1;
190 /* Try to set the server's current time since we didn't do a full
191 TCP LDAP session initially */
193 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
194 d_fprintf( stderr, "Failed to get server's current time!\n");
197 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
199 d_printf("LDAP server: %s\n", addr);
200 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
201 d_printf("Realm: %s\n", ads->config.realm);
202 d_printf("Bind Path: %s\n", ads->config.bind_path);
203 d_printf("LDAP port: %d\n", ads->ldap.port);
204 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
206 d_printf("KDC server: %s\n", ads->auth.kdc_server );
207 d_printf("Server time offset: %d\n", ads->auth.time_offset );
209 return 0;
212 static void use_in_memory_ccache(void) {
213 /* Use in-memory credentials cache so we do not interfere with
214 * existing credentials */
215 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
218 static ADS_STATUS ads_startup_int(bool only_own_domain, uint32 auth_flags, ADS_STRUCT **ads_ret)
220 ADS_STRUCT *ads = NULL;
221 ADS_STATUS status;
222 bool need_password = False;
223 bool second_time = False;
224 char *cp;
225 const char *realm = NULL;
226 bool tried_closest_dc = False;
228 /* lp_realm() should be handled by a command line param,
229 However, the join requires that realm be set in smb.conf
230 and compares our realm with the remote server's so this is
231 ok until someone needs more flexibility */
233 *ads_ret = NULL;
235 retry_connect:
236 if (only_own_domain) {
237 realm = lp_realm();
238 } else {
239 realm = assume_own_realm();
242 ads = ads_init(realm, opt_target_workgroup, opt_host);
244 if (!opt_user_name) {
245 opt_user_name = "administrator";
248 if (opt_user_specified) {
249 need_password = True;
252 retry:
253 if (!opt_password && need_password && !opt_machine_pass) {
254 opt_password = net_prompt_pass(opt_user_name);
255 if (!opt_password) {
256 ads_destroy(&ads);
257 return ADS_ERROR(LDAP_NO_MEMORY);
261 if (opt_password) {
262 use_in_memory_ccache();
263 SAFE_FREE(ads->auth.password);
264 ads->auth.password = smb_xstrdup(opt_password);
267 ads->auth.flags |= auth_flags;
268 SAFE_FREE(ads->auth.user_name);
269 ads->auth.user_name = smb_xstrdup(opt_user_name);
272 * If the username is of the form "name@realm",
273 * extract the realm and convert to upper case.
274 * This is only used to establish the connection.
276 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
277 *cp++ = '\0';
278 SAFE_FREE(ads->auth.realm);
279 ads->auth.realm = smb_xstrdup(cp);
280 strupper_m(ads->auth.realm);
283 status = ads_connect(ads);
285 if (!ADS_ERR_OK(status)) {
287 if (NT_STATUS_EQUAL(ads_ntstatus(status),
288 NT_STATUS_NO_LOGON_SERVERS)) {
289 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
290 ads_destroy(&ads);
291 return status;
294 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
295 need_password = True;
296 second_time = True;
297 goto retry;
298 } else {
299 ads_destroy(&ads);
300 return status;
304 /* when contacting our own domain, make sure we use the closest DC.
305 * This is done by reconnecting to ADS because only the first call to
306 * ads_connect will give us our own sitename */
308 if ((only_own_domain || !opt_host) && !tried_closest_dc) {
310 tried_closest_dc = True; /* avoid loop */
312 if (!ads->config.tried_closest_dc) {
314 namecache_delete(ads->server.realm, 0x1C);
315 namecache_delete(ads->server.workgroup, 0x1C);
317 ads_destroy(&ads);
318 ads = NULL;
320 goto retry_connect;
324 *ads_ret = ads;
325 return status;
328 ADS_STATUS ads_startup(bool only_own_domain, ADS_STRUCT **ads)
330 return ads_startup_int(only_own_domain, 0, ads);
333 ADS_STATUS ads_startup_nobind(bool only_own_domain, ADS_STRUCT **ads)
335 return ads_startup_int(only_own_domain, ADS_AUTH_NO_BIND, ads);
339 Check to see if connection can be made via ads.
340 ads_startup() stores the password in opt_password if it needs to so
341 that rpc or rap can use it without re-prompting.
343 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
345 ADS_STRUCT *ads;
346 ADS_STATUS status;
348 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
349 return -1;
352 ads->auth.flags |= ADS_AUTH_NO_BIND;
354 status = ads_connect(ads);
355 if ( !ADS_ERR_OK(status) ) {
356 return -1;
359 ads_destroy(&ads);
360 return 0;
363 int net_ads_check_our_domain(void)
365 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
368 int net_ads_check(void)
370 return net_ads_check_int(NULL, opt_workgroup, opt_host);
374 determine the netbios workgroup name for a domain
376 static int net_ads_workgroup(int argc, const char **argv)
378 ADS_STRUCT *ads;
379 char addr[INET6_ADDRSTRLEN];
380 struct cldap_netlogon_reply reply;
382 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
383 d_fprintf(stderr, "Didn't find the cldap server!\n");
384 return -1;
387 if (!ads->config.realm) {
388 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
389 ads->ldap.port = 389;
392 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
393 if ( !ads_cldap_netlogon(addr, ads->server.realm, &reply ) ) {
394 d_fprintf(stderr, "CLDAP query failed!\n");
395 return -1;
398 d_printf("Workgroup: %s\n", reply.netbios_domain);
400 ads_destroy(&ads);
402 return 0;
407 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
409 char **disp_fields = (char **) data_area;
411 if (!field) { /* must be end of record */
412 if (disp_fields[0]) {
413 if (!strchr_m(disp_fields[0], '$')) {
414 if (disp_fields[1])
415 d_printf("%-21.21s %s\n",
416 disp_fields[0], disp_fields[1]);
417 else
418 d_printf("%s\n", disp_fields[0]);
421 SAFE_FREE(disp_fields[0]);
422 SAFE_FREE(disp_fields[1]);
423 return True;
425 if (!values) /* must be new field, indicate string field */
426 return True;
427 if (StrCaseCmp(field, "sAMAccountName") == 0) {
428 disp_fields[0] = SMB_STRDUP((char *) values[0]);
430 if (StrCaseCmp(field, "description") == 0)
431 disp_fields[1] = SMB_STRDUP((char *) values[0]);
432 return True;
435 static int net_ads_user_usage(int argc, const char **argv)
437 return net_help_user(argc, argv);
440 static int ads_user_add(int argc, const char **argv)
442 ADS_STRUCT *ads;
443 ADS_STATUS status;
444 char *upn, *userdn;
445 LDAPMessage *res=NULL;
446 int rc = -1;
447 char *ou_str = NULL;
449 if (argc < 1) return net_ads_user_usage(argc, argv);
451 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
452 return -1;
455 status = ads_find_user_acct(ads, &res, argv[0]);
457 if (!ADS_ERR_OK(status)) {
458 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
459 goto done;
462 if (ads_count_replies(ads, res)) {
463 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
464 goto done;
467 if (opt_container) {
468 ou_str = SMB_STRDUP(opt_container);
469 } else {
470 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
473 status = ads_add_user_acct(ads, argv[0], ou_str, opt_comment);
475 if (!ADS_ERR_OK(status)) {
476 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
477 ads_errstr(status));
478 goto done;
481 /* if no password is to be set, we're done */
482 if (argc == 1) {
483 d_printf("User %s added\n", argv[0]);
484 rc = 0;
485 goto done;
488 /* try setting the password */
489 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
490 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
491 ads->auth.time_offset);
492 safe_free(upn);
493 if (ADS_ERR_OK(status)) {
494 d_printf("User %s added\n", argv[0]);
495 rc = 0;
496 goto done;
499 /* password didn't set, delete account */
500 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
501 argv[0], ads_errstr(status));
502 ads_msgfree(ads, res);
503 status=ads_find_user_acct(ads, &res, argv[0]);
504 if (ADS_ERR_OK(status)) {
505 userdn = ads_get_dn(ads, res);
506 ads_del_dn(ads, userdn);
507 ads_memfree(ads, userdn);
510 done:
511 if (res)
512 ads_msgfree(ads, res);
513 ads_destroy(&ads);
514 SAFE_FREE(ou_str);
515 return rc;
518 static int ads_user_info(int argc, const char **argv)
520 ADS_STRUCT *ads;
521 ADS_STATUS rc;
522 LDAPMessage *res;
523 const char *attrs[] = {"memberOf", NULL};
524 char *searchstring=NULL;
525 char **grouplist;
526 char *escaped_user;
528 if (argc < 1) {
529 return net_ads_user_usage(argc, argv);
532 escaped_user = escape_ldap_string_alloc(argv[0]);
534 if (!escaped_user) {
535 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
536 return -1;
539 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
540 SAFE_FREE(escaped_user);
541 return -1;
544 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
545 rc = ads_search(ads, &res, searchstring, attrs);
546 safe_free(searchstring);
548 if (!ADS_ERR_OK(rc)) {
549 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
550 ads_destroy(&ads);
551 SAFE_FREE(escaped_user);
552 return -1;
555 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
556 (LDAPMessage *)res, "memberOf");
558 if (grouplist) {
559 int i;
560 char **groupname;
561 for (i=0;grouplist[i];i++) {
562 groupname = ldap_explode_dn(grouplist[i], 1);
563 d_printf("%s\n", groupname[0]);
564 ldap_value_free(groupname);
566 ldap_value_free(grouplist);
569 ads_msgfree(ads, res);
570 ads_destroy(&ads);
571 SAFE_FREE(escaped_user);
572 return 0;
575 static int ads_user_delete(int argc, const char **argv)
577 ADS_STRUCT *ads;
578 ADS_STATUS rc;
579 LDAPMessage *res = NULL;
580 char *userdn;
582 if (argc < 1) {
583 return net_ads_user_usage(argc, argv);
586 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
587 return -1;
590 rc = ads_find_user_acct(ads, &res, argv[0]);
591 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
592 d_printf("User %s does not exist.\n", argv[0]);
593 ads_msgfree(ads, res);
594 ads_destroy(&ads);
595 return -1;
597 userdn = ads_get_dn(ads, res);
598 ads_msgfree(ads, res);
599 rc = ads_del_dn(ads, userdn);
600 ads_memfree(ads, userdn);
601 if (ADS_ERR_OK(rc)) {
602 d_printf("User %s deleted\n", argv[0]);
603 ads_destroy(&ads);
604 return 0;
606 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
607 ads_errstr(rc));
608 ads_destroy(&ads);
609 return -1;
612 int net_ads_user(int argc, const char **argv)
614 struct functable func[] = {
615 {"ADD", ads_user_add},
616 {"INFO", ads_user_info},
617 {"DELETE", ads_user_delete},
618 {NULL, NULL}
620 ADS_STRUCT *ads;
621 ADS_STATUS rc;
622 const char *shortattrs[] = {"sAMAccountName", NULL};
623 const char *longattrs[] = {"sAMAccountName", "description", NULL};
624 char *disp_fields[2] = {NULL, NULL};
626 if (argc == 0) {
627 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
628 return -1;
631 if (opt_long_list_entries)
632 d_printf("\nUser name Comment"\
633 "\n-----------------------------\n");
635 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
636 LDAP_SCOPE_SUBTREE,
637 "(objectCategory=user)",
638 opt_long_list_entries ? longattrs :
639 shortattrs, usergrp_display,
640 disp_fields);
641 ads_destroy(&ads);
642 return ADS_ERR_OK(rc) ? 0 : -1;
645 return net_run_function(argc, argv, func, net_ads_user_usage);
648 static int net_ads_group_usage(int argc, const char **argv)
650 return net_help_group(argc, argv);
653 static int ads_group_add(int argc, const char **argv)
655 ADS_STRUCT *ads;
656 ADS_STATUS status;
657 LDAPMessage *res=NULL;
658 int rc = -1;
659 char *ou_str = NULL;
661 if (argc < 1) {
662 return net_ads_group_usage(argc, argv);
665 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
666 return -1;
669 status = ads_find_user_acct(ads, &res, argv[0]);
671 if (!ADS_ERR_OK(status)) {
672 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
673 goto done;
676 if (ads_count_replies(ads, res)) {
677 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
678 goto done;
681 if (opt_container) {
682 ou_str = SMB_STRDUP(opt_container);
683 } else {
684 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
687 status = ads_add_group_acct(ads, argv[0], ou_str, opt_comment);
689 if (ADS_ERR_OK(status)) {
690 d_printf("Group %s added\n", argv[0]);
691 rc = 0;
692 } else {
693 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
694 ads_errstr(status));
697 done:
698 if (res)
699 ads_msgfree(ads, res);
700 ads_destroy(&ads);
701 SAFE_FREE(ou_str);
702 return rc;
705 static int ads_group_delete(int argc, const char **argv)
707 ADS_STRUCT *ads;
708 ADS_STATUS rc;
709 LDAPMessage *res = NULL;
710 char *groupdn;
712 if (argc < 1) {
713 return net_ads_group_usage(argc, argv);
716 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
717 return -1;
720 rc = ads_find_user_acct(ads, &res, argv[0]);
721 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
722 d_printf("Group %s does not exist.\n", argv[0]);
723 ads_msgfree(ads, res);
724 ads_destroy(&ads);
725 return -1;
727 groupdn = ads_get_dn(ads, res);
728 ads_msgfree(ads, res);
729 rc = ads_del_dn(ads, groupdn);
730 ads_memfree(ads, groupdn);
731 if (ADS_ERR_OK(rc)) {
732 d_printf("Group %s deleted\n", argv[0]);
733 ads_destroy(&ads);
734 return 0;
736 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
737 ads_errstr(rc));
738 ads_destroy(&ads);
739 return -1;
742 int net_ads_group(int argc, const char **argv)
744 struct functable func[] = {
745 {"ADD", ads_group_add},
746 {"DELETE", ads_group_delete},
747 {NULL, NULL}
749 ADS_STRUCT *ads;
750 ADS_STATUS rc;
751 const char *shortattrs[] = {"sAMAccountName", NULL};
752 const char *longattrs[] = {"sAMAccountName", "description", NULL};
753 char *disp_fields[2] = {NULL, NULL};
755 if (argc == 0) {
756 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
757 return -1;
760 if (opt_long_list_entries)
761 d_printf("\nGroup name Comment"\
762 "\n-----------------------------\n");
763 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
764 LDAP_SCOPE_SUBTREE,
765 "(objectCategory=group)",
766 opt_long_list_entries ? longattrs :
767 shortattrs, usergrp_display,
768 disp_fields);
770 ads_destroy(&ads);
771 return ADS_ERR_OK(rc) ? 0 : -1;
773 return net_run_function(argc, argv, func, net_ads_group_usage);
776 static int net_ads_status(int argc, const char **argv)
778 ADS_STRUCT *ads;
779 ADS_STATUS rc;
780 LDAPMessage *res;
782 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
783 return -1;
786 rc = ads_find_machine_acct(ads, &res, global_myname());
787 if (!ADS_ERR_OK(rc)) {
788 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
789 ads_destroy(&ads);
790 return -1;
793 if (ads_count_replies(ads, res) == 0) {
794 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
795 ads_destroy(&ads);
796 return -1;
799 ads_dump(ads, res);
800 ads_destroy(&ads);
801 return 0;
804 /*******************************************************************
805 Leave an AD domain. Windows XP disables the machine account.
806 We'll try the same. The old code would do an LDAP delete.
807 That only worked using the machine creds because added the machine
808 with full control to the computer object's ACL.
809 *******************************************************************/
811 static int net_ads_leave(int argc, const char **argv)
813 ADS_STRUCT *ads = NULL;
814 ADS_STATUS adsret;
815 NTSTATUS status;
816 int ret = -1;
817 struct cli_state *cli = NULL;
818 TALLOC_CTX *ctx;
819 DOM_SID *dom_sid = NULL;
820 char *short_domain_name = NULL;
822 if (!secrets_init()) {
823 DEBUG(1,("Failed to initialise secrets database\n"));
824 return -1;
827 if (!(ctx = talloc_init("net_ads_leave"))) {
828 d_fprintf(stderr, "Could not initialise talloc context.\n");
829 return -1;
832 /* The finds a DC and takes care of getting the
833 user creds if necessary */
835 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
836 return -1;
839 /* make RPC calls here */
841 if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, &ads->ldap.ss,
842 ads->config.ldap_server_name)) )
844 goto done;
847 if ( !NT_STATUS_IS_OK(netdom_get_domain_sid( ctx, cli, &short_domain_name, &dom_sid )) ) {
848 goto done;
851 saf_delete( short_domain_name );
853 status = netdom_leave_domain(ctx, cli, dom_sid);
855 /* Try and delete it via LDAP - the old way we used to. */
857 adsret = ads_leave_realm(ads, global_myname());
858 if (ADS_ERR_OK(adsret)) {
859 d_printf("Deleted account for '%s' in realm '%s'\n",
860 global_myname(), ads->config.realm);
861 ret = 0;
862 } else {
863 /* We couldn't delete it - see if the disable succeeded. */
864 if (NT_STATUS_IS_OK(status)) {
865 d_printf("Disabled account for '%s' in realm '%s'\n",
866 global_myname(), ads->config.realm);
867 ret = 0;
868 } else {
869 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
870 global_myname(), ads->config.realm);
874 done:
876 if ( cli )
877 cli_shutdown(cli);
879 ads_destroy(&ads);
880 TALLOC_FREE( ctx );
882 return ret;
885 static NTSTATUS net_ads_join_ok(void)
887 ADS_STRUCT *ads = NULL;
888 ADS_STATUS status;
890 if (!secrets_init()) {
891 DEBUG(1,("Failed to initialise secrets database\n"));
892 return NT_STATUS_ACCESS_DENIED;
895 net_use_krb_machine_account();
897 status = ads_startup(True, &ads);
898 if (!ADS_ERR_OK(status)) {
899 return ads_ntstatus(status);
902 ads_destroy(&ads);
903 return NT_STATUS_OK;
907 check that an existing join is OK
909 int net_ads_testjoin(int argc, const char **argv)
911 NTSTATUS status;
912 use_in_memory_ccache();
914 /* Display success or failure */
915 status = net_ads_join_ok();
916 if (!NT_STATUS_IS_OK(status)) {
917 fprintf(stderr,"Join to domain is not valid: %s\n",
918 get_friendly_nt_error_msg(status));
919 return -1;
922 printf("Join is OK\n");
923 return 0;
926 /*******************************************************************
927 Simple configu checks before beginning the join
928 ********************************************************************/
930 static NTSTATUS check_ads_config( void )
932 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
933 d_printf("Host is not configured as a member server.\n");
934 return NT_STATUS_INVALID_DOMAIN_ROLE;
937 if (strlen(global_myname()) > 15) {
938 d_printf("Our netbios name can be at most 15 chars long, "
939 "\"%s\" is %u chars long\n", global_myname(),
940 (unsigned int)strlen(global_myname()));
941 return NT_STATUS_NAME_TOO_LONG;
944 if ( lp_security() == SEC_ADS && !*lp_realm()) {
945 d_fprintf(stderr, "realm must be set in in %s for ADS "
946 "join to succeed.\n", dyn_CONFIGFILE);
947 return NT_STATUS_INVALID_PARAMETER;
950 if (!secrets_init()) {
951 DEBUG(1,("Failed to initialise secrets database\n"));
952 /* This is a good bet for failure of secrets_init ... */
953 return NT_STATUS_ACCESS_DENIED;
956 return NT_STATUS_OK;
959 /*******************************************************************
960 Do the domain join
961 ********************************************************************/
963 static NTSTATUS net_join_domain(TALLOC_CTX *ctx, const char *servername,
964 struct sockaddr_storage *pss, char **domain,
965 DOM_SID **dom_sid,
966 const char *password)
968 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
969 struct cli_state *cli = NULL;
971 ret = connect_to_ipc_krb5(&cli, pss, servername);
972 if ( !NT_STATUS_IS_OK(ret) ) {
973 goto done;
976 ret = netdom_get_domain_sid( ctx, cli, domain, dom_sid );
977 if ( !NT_STATUS_IS_OK(ret) ) {
978 goto done;
981 /* cli->server_domain is not filled in when using krb5
982 session setups */
984 saf_store( *domain, cli->desthost );
986 ret = netdom_join_domain( ctx, cli, *dom_sid, password, ND_TYPE_AD );
988 done:
989 if ( cli )
990 cli_shutdown(cli);
992 return ret;
995 /*******************************************************************
996 Set a machines dNSHostName and servicePrincipalName attributes
997 ********************************************************************/
999 static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
1001 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1002 char *new_dn;
1003 ADS_MODLIST mods;
1004 const char *servicePrincipalName[3] = {NULL, NULL, NULL};
1005 char *psp;
1006 fstring my_fqdn;
1007 LDAPMessage *res = NULL;
1008 char *dn_string = NULL;
1009 const char *machine_name = global_myname();
1010 int count;
1012 if ( !machine_name ) {
1013 return ADS_ERROR(LDAP_NO_MEMORY);
1016 /* Find our DN */
1018 status = ads_find_machine_acct(ads_s, &res, machine_name);
1019 if (!ADS_ERR_OK(status))
1020 return status;
1022 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1023 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1024 return ADS_ERROR(LDAP_NO_MEMORY);
1027 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1028 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1029 goto done;
1032 new_dn = talloc_strdup(ctx, dn_string);
1033 ads_memfree(ads_s, dn_string);
1034 if (!new_dn) {
1035 return ADS_ERROR(LDAP_NO_MEMORY);
1038 /* Windows only creates HOST/shortname & HOST/fqdn. */
1040 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) )
1041 goto done;
1042 strupper_m(psp);
1043 servicePrincipalName[0] = psp;
1045 name_to_fqdn(my_fqdn, machine_name);
1046 strlower_m(my_fqdn);
1047 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) )
1048 goto done;
1049 servicePrincipalName[1] = psp;
1051 if (!(mods = ads_init_mods(ctx))) {
1052 goto done;
1055 /* fields of primary importance */
1057 ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
1058 ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
1060 status = ads_gen_mod(ads_s, new_dn, mods);
1062 done:
1063 ads_msgfree(ads_s, res);
1065 return status;
1068 /*******************************************************************
1069 Set a machines dNSHostName and servicePrincipalName attributes
1070 ********************************************************************/
1072 static ADS_STATUS net_set_machine_upn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, const char *upn )
1074 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1075 char *new_dn;
1076 ADS_MODLIST mods;
1077 LDAPMessage *res = NULL;
1078 char *dn_string = NULL;
1079 const char *machine_name = global_myname();
1080 int count;
1082 if ( !machine_name ) {
1083 return ADS_ERROR(LDAP_NO_MEMORY);
1086 /* Find our DN */
1088 status = ads_find_machine_acct(ads_s, &res, machine_name);
1089 if (!ADS_ERR_OK(status))
1090 return status;
1092 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1093 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1094 return ADS_ERROR(LDAP_NO_MEMORY);
1097 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1098 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1099 goto done;
1102 new_dn = talloc_strdup(ctx, dn_string);
1103 ads_memfree(ads_s, dn_string);
1104 if (!new_dn) {
1105 return ADS_ERROR(LDAP_NO_MEMORY);
1108 /* now do the mods */
1110 if (!(mods = ads_init_mods(ctx))) {
1111 goto done;
1114 /* fields of primary importance */
1116 ads_mod_str(ctx, &mods, "userPrincipalName", upn);
1118 status = ads_gen_mod(ads_s, new_dn, mods);
1120 done:
1121 ads_msgfree(ads_s, res);
1123 return status;
1126 /*******************************************************************
1127 Set a machines dNSHostName and servicePrincipalName attributes
1128 ********************************************************************/
1130 static ADS_STATUS net_set_os_attributes(TALLOC_CTX *ctx, ADS_STRUCT *ads_s,
1131 const char *os_name, const char *os_version )
1133 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1134 char *new_dn;
1135 ADS_MODLIST mods;
1136 LDAPMessage *res = NULL;
1137 char *dn_string = NULL;
1138 const char *machine_name = global_myname();
1139 int count;
1140 char *os_sp = NULL;
1142 if ( !os_name || !os_version ) {
1143 return ADS_ERROR(LDAP_NO_MEMORY);
1146 /* Find our DN */
1148 status = ads_find_machine_acct(ads_s, &res, machine_name);
1149 if (!ADS_ERR_OK(status))
1150 return status;
1152 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1153 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1154 return ADS_ERROR(LDAP_NO_MEMORY);
1157 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1158 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1159 goto done;
1162 new_dn = talloc_strdup(ctx, dn_string);
1163 ads_memfree(ads_s, dn_string);
1164 if (!new_dn) {
1165 return ADS_ERROR(LDAP_NO_MEMORY);
1168 /* now do the mods */
1170 if (!(mods = ads_init_mods(ctx))) {
1171 goto done;
1174 os_sp = talloc_asprintf( ctx, "Samba %s", SAMBA_VERSION_STRING );
1176 /* fields of primary importance */
1178 ads_mod_str(ctx, &mods, "operatingSystem", os_name);
1179 ads_mod_str(ctx, &mods, "operatingSystemVersion", os_version);
1180 if ( os_sp )
1181 ads_mod_str(ctx, &mods, "operatingSystemServicePack", os_sp);
1183 status = ads_gen_mod(ads_s, new_dn, mods);
1185 done:
1186 ads_msgfree(ads_s, res);
1187 TALLOC_FREE( os_sp );
1189 return status;
1192 /*******************************************************************
1193 join a domain using ADS (LDAP mods)
1194 ********************************************************************/
1196 static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
1198 ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
1199 char *ou_str = NULL;
1200 char *dn = NULL;
1201 LDAPMessage *res = NULL;
1202 bool moved;
1204 ou_str = ads_ou_string(ads, ou);
1205 if (asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path) == -1) {
1206 rc = ADS_ERROR(LDAP_NO_MEMORY);
1207 goto done;
1210 rc = ads_search_dn(ads, &res, dn, NULL);
1211 if (!ADS_ERR_OK(rc)) {
1212 d_fprintf(stderr, "The specified OU does not exist.\n");
1213 goto done;
1216 /* Attempt to create the machine account and bail if this fails.
1217 Assume that the admin wants exactly what they requested */
1219 rc = ads_create_machine_acct( ads, global_myname(), dn );
1220 if (ADS_ERR_OK(rc)) {
1221 DEBUG(1, ("machine account created\n"));
1222 goto done;
1224 if ( !(rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS) ) {
1225 DEBUG(1, ("machine account creation failed\n"));
1226 goto done;
1229 rc = ads_move_machine_acct(ads, global_myname(), dn, &moved);
1230 if (!ADS_ERR_OK(rc)) {
1231 DEBUG(1, ("failure to locate/move pre-existing machine account\n"));
1232 goto done;
1235 if (moved) {
1236 d_printf("The machine account was moved into the specified OU.\n");
1237 } else {
1238 d_printf("The machine account already exists in the specified OU.\n");
1241 done:
1242 ads_msgfree(ads, res);
1243 SAFE_FREE( ou_str );
1244 SAFE_FREE( dn );
1246 return rc;
1249 /************************************************************************
1250 ************************************************************************/
1252 static bool net_derive_salting_principal( TALLOC_CTX *ctx, ADS_STRUCT *ads )
1254 uint32 domain_func;
1255 ADS_STATUS status;
1256 fstring salt;
1257 char *std_salt;
1258 LDAPMessage *res = NULL;
1259 const char *machine_name = global_myname();
1261 status = ads_domain_func_level( ads, &domain_func );
1262 if ( !ADS_ERR_OK(status) ) {
1263 DEBUG(2,("Failed to determine domain functional level!\n"));
1264 return False;
1267 /* go ahead and setup the default salt */
1269 if ( (std_salt = kerberos_standard_des_salt()) == NULL ) {
1270 d_fprintf(stderr, "net_derive_salting_principal: failed to obtain stanard DES salt\n");
1271 return False;
1274 fstrcpy( salt, std_salt );
1275 SAFE_FREE( std_salt );
1277 /* if it's a Windows functional domain, we have to look for the UPN */
1279 if ( domain_func == DS_DOMAIN_FUNCTION_2000 ) {
1280 char *upn;
1281 int count;
1283 status = ads_find_machine_acct(ads, &res, machine_name);
1284 if (!ADS_ERR_OK(status)) {
1285 return False;
1288 if ( (count = ads_count_replies(ads, res)) != 1 ) {
1289 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1290 return False;
1293 upn = ads_pull_string(ads, ctx, res, "userPrincipalName");
1294 if ( upn ) {
1295 fstrcpy( salt, upn );
1298 ads_msgfree(ads, res);
1301 return kerberos_secrets_store_des_salt( salt );
1304 /*******************************************************************
1305 Send a DNS update request
1306 *******************************************************************/
1308 #if defined(WITH_DNS_UPDATES)
1309 #include "dns.h"
1310 DNS_ERROR DoDNSUpdate(char *pszServerName,
1311 const char *pszDomainName,
1312 const char *pszHostName,
1313 const struct in_addr *iplist, int num_addrs );
1316 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1317 const char *machine_name,
1318 const struct in_addr *addrs,
1319 int num_addrs)
1321 struct dns_rr_ns *nameservers = NULL;
1322 int ns_count = 0;
1323 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1324 DNS_ERROR dns_err;
1325 fstring dns_server;
1326 const char *dnsdomain = NULL;
1327 char *root_domain = NULL;
1329 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1330 d_printf("No DNS domain configured for %s. "
1331 "Unable to perform DNS Update.\n", machine_name);
1332 status = NT_STATUS_INVALID_PARAMETER;
1333 goto done;
1335 dnsdomain++;
1337 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1338 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1339 /* Child domains often do not have NS records. Look
1340 for the NS record for the forest root domain
1341 (rootDomainNamingContext in therootDSE) */
1343 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1344 LDAPMessage *msg = NULL;
1345 char *root_dn;
1346 ADS_STATUS ads_status;
1348 if ( !ads->ldap.ld ) {
1349 ads_status = ads_connect( ads );
1350 if ( !ADS_ERR_OK(ads_status) ) {
1351 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1352 goto done;
1356 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1357 "(objectclass=*)", rootname_attrs, &msg);
1358 if (!ADS_ERR_OK(ads_status)) {
1359 goto done;
1362 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1363 if ( !root_dn ) {
1364 ads_msgfree( ads, msg );
1365 goto done;
1368 root_domain = ads_build_domain( root_dn );
1370 /* cleanup */
1371 ads_msgfree( ads, msg );
1373 /* try again for NS servers */
1375 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1377 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1378 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1379 "realm\n", ads->config.realm));
1380 goto done;
1383 dnsdomain = root_domain;
1387 /* Now perform the dns update - we'll try non-secure and if we fail,
1388 we'll follow it up with a secure update */
1390 fstrcpy( dns_server, nameservers[0].hostname );
1392 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1393 if (!ERR_DNS_IS_OK(dns_err)) {
1394 status = NT_STATUS_UNSUCCESSFUL;
1397 done:
1399 SAFE_FREE( root_domain );
1401 return status;
1404 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1406 int num_addrs;
1407 struct in_addr *iplist = NULL;
1408 fstring machine_name;
1409 NTSTATUS status;
1411 name_to_fqdn( machine_name, global_myname() );
1412 strlower_m( machine_name );
1414 /* Get our ip address (not the 127.0.0.x address but a real ip
1415 * address) */
1417 num_addrs = get_my_ip_address( &iplist );
1418 if ( num_addrs <= 0 ) {
1419 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1420 "addresses!\n"));
1421 return NT_STATUS_INVALID_PARAMETER;
1424 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1425 iplist, num_addrs);
1426 SAFE_FREE( iplist );
1427 return status;
1429 #endif
1432 /*******************************************************************
1433 utility function to parse an integer parameter from
1434 "parameter = value"
1435 **********************************************************/
1436 static char* get_string_param( const char* param )
1438 char *p;
1440 if ( (p = strchr( param, '=' )) == NULL )
1441 return NULL;
1443 return (p+1);
1446 /*******************************************************************
1447 ********************************************************************/
1449 static int net_ads_join_usage(int argc, const char **argv)
1451 d_printf("net ads join [options]\n");
1452 d_printf("Valid options:\n");
1453 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1454 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1455 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1456 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1457 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1458 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1459 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1460 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1461 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1462 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1463 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1464 d_printf(" the two other attributes.\n");
1466 return -1;
1469 /*******************************************************************
1470 ********************************************************************/
1472 int net_ads_join(int argc, const char **argv)
1474 ADS_STRUCT *ads = NULL;
1475 ADS_STATUS status;
1476 NTSTATUS nt_status;
1477 char *machine_account = NULL;
1478 char *short_domain_name = NULL;
1479 char *tmp_password, *password;
1480 TALLOC_CTX *ctx = NULL;
1481 DOM_SID *domain_sid = NULL;
1482 bool createupn = False;
1483 const char *machineupn = NULL;
1484 const char *create_in_ou = NULL;
1485 int i;
1486 fstring dc_name;
1487 struct sockaddr_storage dcss;
1488 const char *os_name = NULL;
1489 const char *os_version = NULL;
1491 nt_status = check_ads_config();
1492 if (!NT_STATUS_IS_OK(nt_status)) {
1493 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1494 goto fail;
1497 /* find a DC to initialize the server affinity cache */
1499 get_dc_name( lp_workgroup(), lp_realm(), dc_name, &dcss );
1501 status = ads_startup(True, &ads);
1502 if (!ADS_ERR_OK(status)) {
1503 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1504 nt_status = ads_ntstatus(status);
1505 goto fail;
1508 if (strcmp(ads->config.realm, lp_realm()) != 0) {
1509 d_fprintf(stderr, "realm of remote server (%s) and realm in %s "
1510 "(%s) DO NOT match. Aborting join\n",
1511 ads->config.realm, dyn_CONFIGFILE, lp_realm());
1512 nt_status = NT_STATUS_INVALID_PARAMETER;
1513 goto fail;
1516 if (!(ctx = talloc_init("net_ads_join"))) {
1517 d_fprintf(stderr, "Could not initialise talloc context.\n");
1518 nt_status = NT_STATUS_NO_MEMORY;
1519 goto fail;
1522 /* process additional command line args */
1524 for ( i=0; i<argc; i++ ) {
1525 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1526 createupn = True;
1527 machineupn = get_string_param(argv[i]);
1529 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1530 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1531 d_fprintf(stderr, "Please supply a valid OU path.\n");
1532 nt_status = NT_STATUS_INVALID_PARAMETER;
1533 goto fail;
1536 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1537 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1538 d_fprintf(stderr, "Please supply a operating system name.\n");
1539 nt_status = NT_STATUS_INVALID_PARAMETER;
1540 goto fail;
1543 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1544 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1545 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1546 nt_status = NT_STATUS_INVALID_PARAMETER;
1547 goto fail;
1550 else {
1551 d_fprintf(stderr, "Bad option: %s\n", argv[i]);
1552 nt_status = NT_STATUS_INVALID_PARAMETER;
1553 goto fail;
1557 /* If we were given an OU, try to create the machine in
1558 the OU account first and then do the normal RPC join */
1560 if ( create_in_ou ) {
1561 status = net_precreate_machine_acct( ads, create_in_ou );
1562 if ( !ADS_ERR_OK(status) ) {
1563 d_fprintf( stderr, "Failed to pre-create the machine object "
1564 "in OU %s.\n", create_in_ou);
1565 DEBUG(1, ("error calling net_precreate_machine_acct: %s\n",
1566 ads_errstr(status)));
1567 nt_status = ads_ntstatus(status);
1568 goto fail;
1572 /* Do the domain join here */
1574 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1575 password = talloc_strdup(ctx, tmp_password);
1577 nt_status = net_join_domain(ctx, ads->config.ldap_server_name,
1578 &ads->ldap.ss, &short_domain_name, &domain_sid, password);
1579 if ( !NT_STATUS_IS_OK(nt_status) ) {
1580 DEBUG(1, ("call of net_join_domain failed: %s\n",
1581 get_friendly_nt_error_msg(nt_status)));
1582 goto fail;
1585 /* Check the short name of the domain */
1587 if ( !strequal(lp_workgroup(), short_domain_name) ) {
1588 d_printf("The workgroup in %s does not match the short\n", dyn_CONFIGFILE);
1589 d_printf("domain name obtained from the server.\n");
1590 d_printf("Using the name [%s] from the server.\n", short_domain_name);
1591 d_printf("You should set \"workgroup = %s\" in %s.\n",
1592 short_domain_name, dyn_CONFIGFILE);
1595 d_printf("Using short domain name -- %s\n", short_domain_name);
1597 /* HACK ALERT! Store the sid and password under both the lp_workgroup()
1598 value from smb.conf and the string returned from the server. The former is
1599 neede to bootstrap winbindd's first connection to the DC to get the real
1600 short domain name --jerry */
1602 if ( (netdom_store_machine_account( lp_workgroup(), domain_sid, password ) == -1)
1603 || (netdom_store_machine_account( short_domain_name, domain_sid, password ) == -1) )
1605 /* issue an internal error here for now.
1606 * everything else would mean changing tdb routines. */
1607 nt_status = NT_STATUS_INTERNAL_ERROR;
1608 goto fail;
1611 /* Verify that everything is ok */
1613 nt_status = net_rpc_join_ok(short_domain_name,
1614 ads->config.ldap_server_name, &ads->ldap.ss);
1615 if (!NT_STATUS_IS_OK(nt_status)) {
1616 d_fprintf(stderr,
1617 "Failed to verify membership in domain: %s!\n",
1618 nt_errstr(nt_status));
1619 goto fail;
1622 /* create the dNSHostName & servicePrincipalName values */
1624 status = net_set_machine_spn( ctx, ads );
1625 if ( !ADS_ERR_OK(status) ) {
1627 d_fprintf(stderr, "Failed to set servicePrincipalNames. Please ensure that\n");
1628 d_fprintf(stderr, "the DNS domain of this server matches the AD domain,\n");
1629 d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n");
1631 /* Disable the machine account in AD. Better to fail than to leave
1632 a confused admin. */
1634 if ( net_ads_leave( 0, NULL ) != 0 ) {
1635 d_fprintf( stderr, "Failed to disable machine account in AD. Please do so manually.\n");
1638 /* clear out the machine password */
1640 netdom_store_machine_account( lp_workgroup(), domain_sid, "" );
1641 netdom_store_machine_account( short_domain_name, domain_sid, "" );
1643 nt_status = ads_ntstatus(status);
1644 goto fail;
1647 if ( !net_derive_salting_principal( ctx, ads ) ) {
1648 DEBUG(1,("Failed to determine salting principal\n"));
1649 goto fail;
1652 if ( createupn ) {
1653 pstring upn;
1655 /* default to using the short UPN name */
1656 if ( !machineupn ) {
1657 snprintf( upn, sizeof(upn), "host/%s@%s", global_myname(),
1658 ads->config.realm );
1659 machineupn = upn;
1662 status = net_set_machine_upn( ctx, ads, machineupn );
1663 if ( !ADS_ERR_OK(status) ) {
1664 d_fprintf(stderr, "Failed to set userPrincipalName. Are you a Domain Admin?\n");
1668 /* Try to set the operatingSystem attributes if asked */
1670 if ( os_name && os_version ) {
1671 status = net_set_os_attributes( ctx, ads, os_name, os_version );
1672 if ( !ADS_ERR_OK(status) ) {
1673 d_fprintf(stderr, "Failed to set operatingSystem attributes. "
1674 "Are you a Domain Admin?\n");
1678 /* Now build the keytab, using the same ADS connection */
1680 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
1681 DEBUG(1,("Error creating host keytab!\n"));
1684 #if defined(WITH_DNS_UPDATES)
1685 /* We enter this block with user creds */
1686 ads_kdestroy( NULL );
1687 ads_destroy(&ads);
1688 ads = NULL;
1690 if ( (ads = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1691 /* kinit with the machine password */
1693 use_in_memory_ccache();
1694 asprintf( &ads->auth.user_name, "%s$", global_myname() );
1695 ads->auth.password = secrets_fetch_machine_password(
1696 lp_workgroup(), NULL, NULL );
1697 ads->auth.realm = SMB_STRDUP( lp_realm() );
1698 ads_kinit_password( ads );
1701 if ( !ads || !NT_STATUS_IS_OK(net_update_dns( ctx, ads )) ) {
1702 d_fprintf( stderr, "DNS update failed!\n" );
1705 /* exit from this block using machine creds */
1706 #endif
1708 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->server.realm);
1710 SAFE_FREE(machine_account);
1711 TALLOC_FREE( ctx );
1712 ads_destroy(&ads);
1714 return 0;
1716 fail:
1717 /* issue an overall failure message at the end. */
1718 d_printf("Failed to join domain: %s\n", get_friendly_nt_error_msg(nt_status));
1720 SAFE_FREE(machine_account);
1721 TALLOC_FREE( ctx );
1722 ads_destroy(&ads);
1724 return -1;
1728 /*******************************************************************
1729 ********************************************************************/
1731 static int net_ads_dns_usage(int argc, const char **argv)
1733 #if defined(WITH_DNS_UPDATES)
1734 d_printf("net ads dns <command>\n");
1735 d_printf("Valid commands:\n");
1736 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1738 return 0;
1739 #else
1740 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1741 return -1;
1742 #endif
1745 /*******************************************************************
1746 ********************************************************************/
1748 static int net_ads_dns_register(int argc, const char **argv)
1750 #if defined(WITH_DNS_UPDATES)
1751 ADS_STRUCT *ads;
1752 ADS_STATUS status;
1753 TALLOC_CTX *ctx;
1755 #ifdef DEVELOPER
1756 talloc_enable_leak_report();
1757 #endif
1759 if (argc > 0) {
1760 d_fprintf(stderr, "net ads dns register\n");
1761 return -1;
1764 if (!(ctx = talloc_init("net_ads_dns"))) {
1765 d_fprintf(stderr, "Could not initialise talloc context\n");
1766 return -1;
1769 status = ads_startup(True, &ads);
1770 if ( !ADS_ERR_OK(status) ) {
1771 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1772 TALLOC_FREE(ctx);
1773 return -1;
1776 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1777 d_fprintf( stderr, "DNS update failed!\n" );
1778 ads_destroy( &ads );
1779 TALLOC_FREE( ctx );
1780 return -1;
1783 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1785 ads_destroy(&ads);
1786 TALLOC_FREE( ctx );
1788 return 0;
1789 #else
1790 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1791 return -1;
1792 #endif
1795 #if defined(WITH_DNS_UPDATES)
1796 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1797 #endif
1799 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1801 #if defined(WITH_DNS_UPDATES)
1802 DNS_ERROR err;
1804 #ifdef DEVELOPER
1805 talloc_enable_leak_report();
1806 #endif
1808 if (argc != 2) {
1809 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1810 "<name>\n");
1811 return -1;
1814 err = do_gethostbyname(argv[0], argv[1]);
1816 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1817 #endif
1818 return 0;
1821 static int net_ads_dns(int argc, const char *argv[])
1823 struct functable func[] = {
1824 {"REGISTER", net_ads_dns_register},
1825 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1826 {NULL, NULL}
1829 return net_run_function(argc, argv, func, net_ads_dns_usage);
1832 /*******************************************************************
1833 ********************************************************************/
1835 int net_ads_printer_usage(int argc, const char **argv)
1837 d_printf(
1838 "\nnet ads printer search <printer>"
1839 "\n\tsearch for a printer in the directory\n"
1840 "\nnet ads printer info <printer> <server>"
1841 "\n\tlookup info in directory for printer on server"
1842 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1843 "\nnet ads printer publish <printername>"
1844 "\n\tpublish printer in directory"
1845 "\n\t(note: printer name is required)\n"
1846 "\nnet ads printer remove <printername>"
1847 "\n\tremove printer from directory"
1848 "\n\t(note: printer name is required)\n");
1849 return -1;
1852 /*******************************************************************
1853 ********************************************************************/
1855 static int net_ads_printer_search(int argc, const char **argv)
1857 ADS_STRUCT *ads;
1858 ADS_STATUS rc;
1859 LDAPMessage *res = NULL;
1861 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1862 return -1;
1865 rc = ads_find_printers(ads, &res);
1867 if (!ADS_ERR_OK(rc)) {
1868 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1869 ads_msgfree(ads, res);
1870 ads_destroy(&ads);
1871 return -1;
1874 if (ads_count_replies(ads, res) == 0) {
1875 d_fprintf(stderr, "No results found\n");
1876 ads_msgfree(ads, res);
1877 ads_destroy(&ads);
1878 return -1;
1881 ads_dump(ads, res);
1882 ads_msgfree(ads, res);
1883 ads_destroy(&ads);
1884 return 0;
1887 static int net_ads_printer_info(int argc, const char **argv)
1889 ADS_STRUCT *ads;
1890 ADS_STATUS rc;
1891 const char *servername, *printername;
1892 LDAPMessage *res = NULL;
1894 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1895 return -1;
1898 if (argc > 0) {
1899 printername = argv[0];
1900 } else {
1901 printername = "*";
1904 if (argc > 1) {
1905 servername = argv[1];
1906 } else {
1907 servername = global_myname();
1910 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1912 if (!ADS_ERR_OK(rc)) {
1913 d_fprintf(stderr, "Server '%s' not found: %s\n",
1914 servername, ads_errstr(rc));
1915 ads_msgfree(ads, res);
1916 ads_destroy(&ads);
1917 return -1;
1920 if (ads_count_replies(ads, res) == 0) {
1921 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1922 ads_msgfree(ads, res);
1923 ads_destroy(&ads);
1924 return -1;
1927 ads_dump(ads, res);
1928 ads_msgfree(ads, res);
1929 ads_destroy(&ads);
1931 return 0;
1934 static int net_ads_printer_publish(int argc, const char **argv)
1936 ADS_STRUCT *ads;
1937 ADS_STATUS rc;
1938 const char *servername, *printername;
1939 struct cli_state *cli;
1940 struct rpc_pipe_client *pipe_hnd;
1941 struct sockaddr_storage server_ss;
1942 NTSTATUS nt_status;
1943 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1944 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1945 char *prt_dn, *srv_dn, **srv_cn;
1946 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1947 LDAPMessage *res = NULL;
1949 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1950 talloc_destroy(mem_ctx);
1951 return -1;
1954 if (argc < 1) {
1955 talloc_destroy(mem_ctx);
1956 return net_ads_printer_usage(argc, argv);
1959 printername = argv[0];
1961 if (argc == 2) {
1962 servername = argv[1];
1963 } else {
1964 servername = global_myname();
1967 /* Get printer data from SPOOLSS */
1969 resolve_name(servername, &server_ss, 0x20);
1971 nt_status = cli_full_connection(&cli, global_myname(), servername,
1972 &server_ss, 0,
1973 "IPC$", "IPC",
1974 opt_user_name, opt_workgroup,
1975 opt_password ? opt_password : "",
1976 CLI_FULL_CONNECTION_USE_KERBEROS,
1977 Undefined, NULL);
1979 if (NT_STATUS_IS_ERR(nt_status)) {
1980 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1981 "for %s\n", servername, printername);
1982 ads_destroy(&ads);
1983 talloc_destroy(mem_ctx);
1984 return -1;
1987 /* Publish on AD server */
1989 ads_find_machine_acct(ads, &res, servername);
1991 if (ads_count_replies(ads, res) == 0) {
1992 d_fprintf(stderr, "Could not find machine account for server %s\n",
1993 servername);
1994 ads_destroy(&ads);
1995 talloc_destroy(mem_ctx);
1996 return -1;
1999 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2000 srv_cn = ldap_explode_dn(srv_dn, 1);
2002 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2003 printername_escaped = escape_rdn_val_string_alloc(printername);
2004 if (!srv_cn_escaped || !printername_escaped) {
2005 SAFE_FREE(srv_cn_escaped);
2006 SAFE_FREE(printername_escaped);
2007 d_fprintf(stderr, "Internal error, out of memory!");
2008 ads_destroy(&ads);
2009 talloc_destroy(mem_ctx);
2010 return -1;
2013 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
2015 SAFE_FREE(srv_cn_escaped);
2016 SAFE_FREE(printername_escaped);
2018 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
2019 if (!pipe_hnd) {
2020 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
2021 servername);
2022 SAFE_FREE(prt_dn);
2023 ads_destroy(&ads);
2024 talloc_destroy(mem_ctx);
2025 return -1;
2028 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
2029 printername))) {
2030 SAFE_FREE(prt_dn);
2031 ads_destroy(&ads);
2032 talloc_destroy(mem_ctx);
2033 return -1;
2036 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
2037 if (!ADS_ERR_OK(rc)) {
2038 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
2039 SAFE_FREE(prt_dn);
2040 ads_destroy(&ads);
2041 talloc_destroy(mem_ctx);
2042 return -1;
2045 d_printf("published printer\n");
2046 SAFE_FREE(prt_dn);
2047 ads_destroy(&ads);
2048 talloc_destroy(mem_ctx);
2050 return 0;
2053 static int net_ads_printer_remove(int argc, const char **argv)
2055 ADS_STRUCT *ads;
2056 ADS_STATUS rc;
2057 const char *servername;
2058 char *prt_dn;
2059 LDAPMessage *res = NULL;
2061 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2062 return -1;
2065 if (argc < 1) {
2066 return net_ads_printer_usage(argc, argv);
2069 if (argc > 1) {
2070 servername = argv[1];
2071 } else {
2072 servername = global_myname();
2075 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2077 if (!ADS_ERR_OK(rc)) {
2078 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
2079 ads_msgfree(ads, res);
2080 ads_destroy(&ads);
2081 return -1;
2084 if (ads_count_replies(ads, res) == 0) {
2085 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
2086 ads_msgfree(ads, res);
2087 ads_destroy(&ads);
2088 return -1;
2091 prt_dn = ads_get_dn(ads, res);
2092 ads_msgfree(ads, res);
2093 rc = ads_del_dn(ads, prt_dn);
2094 ads_memfree(ads, prt_dn);
2096 if (!ADS_ERR_OK(rc)) {
2097 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
2098 ads_destroy(&ads);
2099 return -1;
2102 ads_destroy(&ads);
2103 return 0;
2106 static int net_ads_printer(int argc, const char **argv)
2108 struct functable func[] = {
2109 {"SEARCH", net_ads_printer_search},
2110 {"INFO", net_ads_printer_info},
2111 {"PUBLISH", net_ads_printer_publish},
2112 {"REMOVE", net_ads_printer_remove},
2113 {NULL, NULL}
2116 return net_run_function(argc, argv, func, net_ads_printer_usage);
2120 static int net_ads_password(int argc, const char **argv)
2122 ADS_STRUCT *ads;
2123 const char *auth_principal = opt_user_name;
2124 const char *auth_password = opt_password;
2125 char *realm = NULL;
2126 char *new_password = NULL;
2127 char *c, *prompt;
2128 const char *user;
2129 ADS_STATUS ret;
2131 if (opt_user_name == NULL || opt_password == NULL) {
2132 d_fprintf(stderr, "You must supply an administrator username/password\n");
2133 return -1;
2136 if (argc < 1) {
2137 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
2138 return -1;
2141 user = argv[0];
2142 if (!strchr_m(user, '@')) {
2143 asprintf(&c, "%s@%s", argv[0], lp_realm());
2144 user = c;
2147 use_in_memory_ccache();
2148 c = strchr_m(auth_principal, '@');
2149 if (c) {
2150 realm = ++c;
2151 } else {
2152 realm = lp_realm();
2155 /* use the realm so we can eventually change passwords for users
2156 in realms other than default */
2157 if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
2158 return -1;
2161 /* we don't actually need a full connect, but it's the easy way to
2162 fill in the KDC's addresss */
2163 ads_connect(ads);
2165 if (!ads || !ads->config.realm) {
2166 d_fprintf(stderr, "Didn't find the kerberos server!\n");
2167 return -1;
2170 if (argv[1]) {
2171 new_password = (char *)argv[1];
2172 } else {
2173 asprintf(&prompt, "Enter new password for %s:", user);
2174 new_password = getpass(prompt);
2175 free(prompt);
2178 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2179 auth_password, user, new_password, ads->auth.time_offset);
2180 if (!ADS_ERR_OK(ret)) {
2181 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
2182 ads_destroy(&ads);
2183 return -1;
2186 d_printf("Password change for %s completed.\n", user);
2187 ads_destroy(&ads);
2189 return 0;
2192 int net_ads_changetrustpw(int argc, const char **argv)
2194 ADS_STRUCT *ads;
2195 char *host_principal;
2196 fstring my_name;
2197 ADS_STATUS ret;
2199 if (!secrets_init()) {
2200 DEBUG(1,("Failed to initialise secrets database\n"));
2201 return -1;
2204 net_use_krb_machine_account();
2206 use_in_memory_ccache();
2208 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2209 return -1;
2212 fstrcpy(my_name, global_myname());
2213 strlower_m(my_name);
2214 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
2215 d_printf("Changing password for principal: %s\n", host_principal);
2217 ret = ads_change_trust_account_password(ads, host_principal);
2219 if (!ADS_ERR_OK(ret)) {
2220 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
2221 ads_destroy(&ads);
2222 SAFE_FREE(host_principal);
2223 return -1;
2226 d_printf("Password change for principal %s succeeded.\n", host_principal);
2228 if (lp_use_kerberos_keytab()) {
2229 d_printf("Attempting to update system keytab with new password.\n");
2230 if (ads_keytab_create_default(ads)) {
2231 d_printf("Failed to update system keytab.\n");
2235 ads_destroy(&ads);
2236 SAFE_FREE(host_principal);
2238 return 0;
2242 help for net ads search
2244 static int net_ads_search_usage(int argc, const char **argv)
2246 d_printf(
2247 "\nnet ads search <expression> <attributes...>\n"\
2248 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2249 "The expression is a standard LDAP search expression, and the\n"\
2250 "attributes are a list of LDAP fields to show in the results\n\n"\
2251 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2253 net_common_flags_usage(argc, argv);
2254 return -1;
2259 general ADS search function. Useful in diagnosing problems in ADS
2261 static int net_ads_search(int argc, const char **argv)
2263 ADS_STRUCT *ads;
2264 ADS_STATUS rc;
2265 const char *ldap_exp;
2266 const char **attrs;
2267 LDAPMessage *res = NULL;
2269 if (argc < 1) {
2270 return net_ads_search_usage(argc, argv);
2273 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2274 return -1;
2277 ldap_exp = argv[0];
2278 attrs = (argv + 1);
2280 rc = ads_do_search_all(ads, ads->config.bind_path,
2281 LDAP_SCOPE_SUBTREE,
2282 ldap_exp, attrs, &res);
2283 if (!ADS_ERR_OK(rc)) {
2284 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2285 ads_destroy(&ads);
2286 return -1;
2289 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2291 /* dump the results */
2292 ads_dump(ads, res);
2294 ads_msgfree(ads, res);
2295 ads_destroy(&ads);
2297 return 0;
2302 help for net ads search
2304 static int net_ads_dn_usage(int argc, const char **argv)
2306 d_printf(
2307 "\nnet ads dn <dn> <attributes...>\n"\
2308 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2309 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
2310 "to show in the results\n\n"\
2311 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2312 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2314 net_common_flags_usage(argc, argv);
2315 return -1;
2320 general ADS search function. Useful in diagnosing problems in ADS
2322 static int net_ads_dn(int argc, const char **argv)
2324 ADS_STRUCT *ads;
2325 ADS_STATUS rc;
2326 const char *dn;
2327 const char **attrs;
2328 LDAPMessage *res = NULL;
2330 if (argc < 1) {
2331 return net_ads_dn_usage(argc, argv);
2334 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2335 return -1;
2338 dn = argv[0];
2339 attrs = (argv + 1);
2341 rc = ads_do_search_all(ads, dn,
2342 LDAP_SCOPE_BASE,
2343 "(objectclass=*)", attrs, &res);
2344 if (!ADS_ERR_OK(rc)) {
2345 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2346 ads_destroy(&ads);
2347 return -1;
2350 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2352 /* dump the results */
2353 ads_dump(ads, res);
2355 ads_msgfree(ads, res);
2356 ads_destroy(&ads);
2358 return 0;
2362 help for net ads sid search
2364 static int net_ads_sid_usage(int argc, const char **argv)
2366 d_printf(
2367 "\nnet ads sid <sid> <attributes...>\n"\
2368 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2369 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
2370 "to show in the results\n\n"\
2371 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2373 net_common_flags_usage(argc, argv);
2374 return -1;
2379 general ADS search function. Useful in diagnosing problems in ADS
2381 static int net_ads_sid(int argc, const char **argv)
2383 ADS_STRUCT *ads;
2384 ADS_STATUS rc;
2385 const char *sid_string;
2386 const char **attrs;
2387 LDAPMessage *res = NULL;
2388 DOM_SID sid;
2390 if (argc < 1) {
2391 return net_ads_sid_usage(argc, argv);
2394 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2395 return -1;
2398 sid_string = argv[0];
2399 attrs = (argv + 1);
2401 if (!string_to_sid(&sid, sid_string)) {
2402 d_fprintf(stderr, "could not convert sid\n");
2403 ads_destroy(&ads);
2404 return -1;
2407 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2408 if (!ADS_ERR_OK(rc)) {
2409 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2410 ads_destroy(&ads);
2411 return -1;
2414 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2416 /* dump the results */
2417 ads_dump(ads, res);
2419 ads_msgfree(ads, res);
2420 ads_destroy(&ads);
2422 return 0;
2426 static int net_ads_keytab_usage(int argc, const char **argv)
2428 d_printf(
2429 "net ads keytab <COMMAND>\n"\
2430 "<COMMAND> can be either:\n"\
2431 " ADD Adds new service principal\n"\
2432 " CREATE Creates a fresh keytab\n"\
2433 " FLUSH Flushes out all keytab entries\n"\
2434 " HELP Prints this help message\n"\
2435 " LIST List the keytab\n"\
2436 "The ADD and LIST command will take arguments, the other commands\n"\
2437 "will not take any arguments. The arguments given to ADD\n"\
2438 "should be a list of principals to add. For example, \n"\
2439 " net ads keytab add srv1 srv2\n"\
2440 "will add principals for the services srv1 and srv2 to the\n"\
2441 "system's keytab.\n"\
2442 "The LIST command takes a keytabname.\n"\
2443 "\n"
2445 return -1;
2448 static int net_ads_keytab_flush(int argc, const char **argv)
2450 int ret;
2451 ADS_STRUCT *ads;
2453 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2454 return -1;
2456 ret = ads_keytab_flush(ads);
2457 ads_destroy(&ads);
2458 return ret;
2461 static int net_ads_keytab_add(int argc, const char **argv)
2463 int i;
2464 int ret = 0;
2465 ADS_STRUCT *ads;
2467 d_printf("Processing principals to add...\n");
2468 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2469 return -1;
2471 for (i = 0; i < argc; i++) {
2472 ret |= ads_keytab_add_entry(ads, argv[i]);
2474 ads_destroy(&ads);
2475 return ret;
2478 static int net_ads_keytab_create(int argc, const char **argv)
2480 ADS_STRUCT *ads;
2481 int ret;
2483 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2484 return -1;
2486 ret = ads_keytab_create_default(ads);
2487 ads_destroy(&ads);
2488 return ret;
2491 static int net_ads_keytab_list(int argc, const char **argv)
2493 const char *keytab = NULL;
2495 if (argc >= 1) {
2496 keytab = argv[0];
2499 return ads_keytab_list(keytab);
2503 int net_ads_keytab(int argc, const char **argv)
2505 struct functable func[] = {
2506 {"ADD", net_ads_keytab_add},
2507 {"CREATE", net_ads_keytab_create},
2508 {"FLUSH", net_ads_keytab_flush},
2509 {"HELP", net_ads_keytab_usage},
2510 {"LIST", net_ads_keytab_list},
2511 {NULL, NULL}
2514 if (!lp_use_kerberos_keytab()) {
2515 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2516 use keytab functions.\n");
2519 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2522 static int net_ads_kerberos_usage(int argc, const char **argv)
2524 d_printf(
2525 "net ads kerberos <COMMAND>\n"\
2526 "<COMMAND> can be either:\n"\
2527 " RENEW Renew TGT from existing credential cache\n"\
2528 " PAC Dumps the Kerberos PAC\n"\
2529 " KINIT Retrieve Ticket Granting Ticket (TGT)\n"\
2530 "\n"
2533 return -1;
2536 static int net_ads_kerberos_renew(int argc, const char **argv)
2538 int ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2539 if (ret) {
2540 d_printf("failed to renew kerberos ticket: %s\n",
2541 error_message(ret));
2543 return ret;
2546 static int net_ads_kerberos_pac(int argc, const char **argv)
2548 PAC_DATA *pac = NULL;
2549 PAC_LOGON_INFO *info = NULL;
2550 TALLOC_CTX *mem_ctx = NULL;
2551 NTSTATUS status;
2552 int ret = -1;
2554 mem_ctx = talloc_init("net_ads_kerberos_pac");
2555 if (!mem_ctx) {
2556 goto out;
2559 opt_password = net_prompt_pass(opt_user_name);
2561 status = kerberos_return_pac(mem_ctx,
2562 opt_user_name,
2563 opt_password,
2565 NULL,
2566 NULL,
2567 NULL,
2568 True,
2569 True,
2570 2592000, /* one month */
2571 &pac);
2572 if (!NT_STATUS_IS_OK(status)) {
2573 d_printf("failed to query kerberos PAC: %s\n",
2574 nt_errstr(status));
2575 goto out;
2578 info = get_logon_info_from_pac(pac);
2579 if (info) {
2580 dump_pac_logon_info(0, info);
2583 ret = 0;
2584 out:
2585 TALLOC_FREE(mem_ctx);
2586 return ret;
2589 static int net_ads_kerberos_kinit(int argc, const char **argv)
2591 TALLOC_CTX *mem_ctx = NULL;
2592 int ret = -1;
2593 NTSTATUS status;
2595 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2596 if (!mem_ctx) {
2597 goto out;
2600 opt_password = net_prompt_pass(opt_user_name);
2602 ret = kerberos_kinit_password_ext(opt_user_name,
2603 opt_password,
2605 NULL,
2606 NULL,
2607 NULL,
2608 True,
2609 True,
2610 2592000, /* one month */
2611 &status);
2612 if (ret) {
2613 d_printf("failed to kinit password: %s\n",
2614 nt_errstr(status));
2616 out:
2617 return ret;
2620 int net_ads_kerberos(int argc, const char **argv)
2622 struct functable func[] = {
2623 {"KINIT", net_ads_kerberos_kinit},
2624 {"RENEW", net_ads_kerberos_renew},
2625 {"PAC", net_ads_kerberos_pac},
2626 {"HELP", net_ads_kerberos_usage},
2627 {NULL, NULL}
2630 return net_run_function(argc, argv, func, net_ads_kerberos_usage);
2634 int net_ads_help(int argc, const char **argv)
2636 struct functable func[] = {
2637 {"USER", net_ads_user_usage},
2638 {"GROUP", net_ads_group_usage},
2639 {"PRINTER", net_ads_printer_usage},
2640 {"SEARCH", net_ads_search_usage},
2641 {"INFO", net_ads_info},
2642 {"JOIN", net_ads_join_usage},
2643 {"DNS", net_ads_dns_usage},
2644 {"LEAVE", net_ads_leave},
2645 {"STATUS", net_ads_status},
2646 {"PASSWORD", net_ads_password},
2647 {"CHANGETRUSTPW", net_ads_changetrustpw},
2648 {NULL, NULL}
2651 return net_run_function(argc, argv, func, net_ads_usage);
2654 int net_ads(int argc, const char **argv)
2656 struct functable func[] = {
2657 {"INFO", net_ads_info},
2658 {"JOIN", net_ads_join},
2659 {"TESTJOIN", net_ads_testjoin},
2660 {"LEAVE", net_ads_leave},
2661 {"STATUS", net_ads_status},
2662 {"USER", net_ads_user},
2663 {"GROUP", net_ads_group},
2664 {"DNS", net_ads_dns},
2665 {"PASSWORD", net_ads_password},
2666 {"CHANGETRUSTPW", net_ads_changetrustpw},
2667 {"PRINTER", net_ads_printer},
2668 {"SEARCH", net_ads_search},
2669 {"DN", net_ads_dn},
2670 {"SID", net_ads_sid},
2671 {"WORKGROUP", net_ads_workgroup},
2672 {"LOOKUP", net_ads_lookup},
2673 {"KEYTAB", net_ads_keytab},
2674 {"GPO", net_ads_gpo},
2675 {"KERBEROS", net_ads_kerberos},
2676 {"HELP", net_ads_help},
2677 {NULL, NULL}
2680 return net_run_function(argc, argv, func, net_ads_usage);
2683 #else
2685 static int net_ads_noads(void)
2687 d_fprintf(stderr, "ADS support not compiled in\n");
2688 return -1;
2691 int net_ads_keytab(int argc, const char **argv)
2693 return net_ads_noads();
2696 int net_ads_kerberos(int argc, const char **argv)
2698 return net_ads_noads();
2701 int net_ads_usage(int argc, const char **argv)
2703 return net_ads_noads();
2706 int net_ads_help(int argc, const char **argv)
2708 return net_ads_noads();
2711 int net_ads_changetrustpw(int argc, const char **argv)
2713 return net_ads_noads();
2716 int net_ads_join(int argc, const char **argv)
2718 return net_ads_noads();
2721 int net_ads_user(int argc, const char **argv)
2723 return net_ads_noads();
2726 int net_ads_group(int argc, const char **argv)
2728 return net_ads_noads();
2731 /* this one shouldn't display a message */
2732 int net_ads_check(void)
2734 return -1;
2737 int net_ads_check_our_domain(void)
2739 return -1;
2742 int net_ads(int argc, const char **argv)
2744 return net_ads_usage(argc, argv);
2747 #endif /* WITH_ADS */