r3780: final release notes
[Samba.git] / source / utils / net_ads.c
blob9efa45e58f566667dc1745c3691aa89f87d5e16d
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)
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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(
31 "\nnet ads join <org_unit>"\
32 "\n\tjoins the local machine to a ADS realm\n"\
33 "\nnet ads leave"\
34 "\n\tremoves the local machine from a ADS realm\n"\
35 "\nnet ads testjoin"\
36 "\n\ttests that an exiting join is OK\n"\
37 "\nnet ads user"\
38 "\n\tlist, add, or delete users in the realm\n"\
39 "\nnet ads group"\
40 "\n\tlist, add, or delete groups in the realm\n"\
41 "\nnet ads info"\
42 "\n\tshows some info on the server\n"\
43 "\nnet ads status"\
44 "\n\tdump the machine account details to stdout\n"
45 "\nnet ads lookup"\
46 "\n\tperform a CLDAP search on the server\n"
47 "\nnet ads password <username@realm> <password> -Uadmin_username@realm%%admin_pass"\
48 "\n\tchange a user's password using an admin account"\
49 "\n\t(note: use realm in UPPERCASE, prompts if password is obmitted)\n"\
50 "\nnet ads changetrustpw"\
51 "\n\tchange the trust account password of this machine in the AD tree\n"\
52 "\nnet ads printer [info | publish | remove] <printername> <servername>"\
53 "\n\t lookup, add, or remove directory entry for a printer\n"\
54 "\nnet ads search"\
55 "\n\tperform a raw LDAP search and dump the results\n"
56 "\nnet ads dn"\
57 "\n\tperform a raw LDAP search and dump attributes of a particular DN\n"
58 "\nnet ads keytab"\
59 "\n\tcreates and updates the kerberos system keytab file\n"
61 return -1;
66 this implements the CLDAP based netlogon lookup requests
67 for finding the domain controller of a ADS domain
69 static int net_ads_lookup(int argc, const char **argv)
71 ADS_STRUCT *ads;
73 ads = ads_init(NULL, opt_target_workgroup, opt_host);
74 if (ads) {
75 ads->auth.flags |= ADS_AUTH_NO_BIND;
78 ads_connect(ads);
80 if (!ads) {
81 d_printf("Didn't find the cldap server!\n");
82 return -1;
83 } if (!ads->config.realm) {
84 ads->config.realm = opt_target_workgroup;
85 ads->ldap_port = 389;
88 return ads_cldap_netlogon(ads);
93 static int net_ads_info(int argc, const char **argv)
95 ADS_STRUCT *ads;
97 ads = ads_init(NULL, opt_target_workgroup, opt_host);
99 if (ads) {
100 ads->auth.flags |= ADS_AUTH_NO_BIND;
103 ads_connect(ads);
105 if (!ads || !ads->config.realm) {
106 d_printf("Didn't find the ldap server!\n");
107 return -1;
110 d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
111 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
112 d_printf("Realm: %s\n", ads->config.realm);
113 d_printf("Bind Path: %s\n", ads->config.bind_path);
114 d_printf("LDAP port: %d\n", ads->ldap_port);
115 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
117 d_printf("KDC server: %s\n", ads->auth.kdc_server );
118 d_printf("Server time offset: %d\n", ads->auth.time_offset );
120 return 0;
123 static void use_in_memory_ccache(void) {
124 /* Use in-memory credentials cache so we do not interfere with
125 * existing credentials */
126 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
129 static ADS_STRUCT *ads_startup(void)
131 ADS_STRUCT *ads;
132 ADS_STATUS status;
133 BOOL need_password = False;
134 BOOL second_time = False;
135 char *cp;
137 /* lp_realm() should be handled by a command line param,
138 However, the join requires that realm be set in smb.conf
139 and compares our realm with the remote server's so this is
140 ok until someone needs more flexibility */
142 ads = ads_init(lp_realm(), opt_target_workgroup, opt_host);
144 if (!opt_user_name) {
145 opt_user_name = "administrator";
148 if (opt_user_specified) {
149 need_password = True;
152 retry:
153 if (!opt_password && need_password && !opt_machine_pass) {
154 char *prompt;
155 asprintf(&prompt,"%s's password: ", opt_user_name);
156 opt_password = getpass(prompt);
157 free(prompt);
160 if (opt_password) {
161 use_in_memory_ccache();
162 ads->auth.password = smb_xstrdup(opt_password);
165 ads->auth.user_name = smb_xstrdup(opt_user_name);
168 * If the username is of the form "name@realm",
169 * extract the realm and convert to upper case.
170 * This is only used to establish the connection.
172 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
173 *cp++ = '\0';
174 ads->auth.realm = smb_xstrdup(cp);
175 strupper_m(ads->auth.realm);
178 status = ads_connect(ads);
180 if (!ADS_ERR_OK(status)) {
181 if (!need_password && !second_time) {
182 need_password = True;
183 second_time = True;
184 goto retry;
185 } else {
186 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
187 return NULL;
190 return ads;
195 Check to see if connection can be made via ads.
196 ads_startup() stores the password in opt_password if it needs to so
197 that rpc or rap can use it without re-prompting.
199 int net_ads_check(void)
201 ADS_STRUCT *ads;
203 ads = ads_startup();
204 if (!ads)
205 return -1;
206 ads_destroy(&ads);
207 return 0;
211 determine the netbios workgroup name for a domain
213 static int net_ads_workgroup(int argc, const char **argv)
215 ADS_STRUCT *ads;
216 TALLOC_CTX *ctx;
217 const char *workgroup;
219 if (!(ads = ads_startup())) return -1;
221 if (!(ctx = talloc_init("net_ads_workgroup"))) {
222 ads_destroy(&ads);
223 return -1;
226 if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
227 d_printf("Failed to find workgroup for realm '%s'\n",
228 ads->config.realm);
229 talloc_destroy(ctx);
230 ads_destroy(&ads);
231 return -1;
234 d_printf("Workgroup: %s\n", workgroup);
236 talloc_destroy(ctx);
237 ads_destroy(&ads);
238 return 0;
243 static BOOL usergrp_display(char *field, void **values, void *data_area)
245 char **disp_fields = (char **) data_area;
247 if (!field) { /* must be end of record */
248 if (!strchr_m(disp_fields[0], '$')) {
249 if (disp_fields[1])
250 d_printf("%-21.21s %s\n",
251 disp_fields[0], disp_fields[1]);
252 else
253 d_printf("%s\n", disp_fields[0]);
255 SAFE_FREE(disp_fields[0]);
256 SAFE_FREE(disp_fields[1]);
257 return True;
259 if (!values) /* must be new field, indicate string field */
260 return True;
261 if (StrCaseCmp(field, "sAMAccountName") == 0) {
262 disp_fields[0] = strdup((char *) values[0]);
264 if (StrCaseCmp(field, "description") == 0)
265 disp_fields[1] = strdup((char *) values[0]);
266 return True;
269 static int net_ads_user_usage(int argc, const char **argv)
271 return net_help_user(argc, argv);
274 static int ads_user_add(int argc, const char **argv)
276 ADS_STRUCT *ads;
277 ADS_STATUS status;
278 char *upn, *userdn;
279 void *res=NULL;
280 int rc = -1;
282 if (argc < 1) return net_ads_user_usage(argc, argv);
284 if (!(ads = ads_startup())) {
285 return -1;
288 status = ads_find_user_acct(ads, &res, argv[0]);
290 if (!ADS_ERR_OK(status)) {
291 d_printf("ads_user_add: %s\n", ads_errstr(status));
292 goto done;
295 if (ads_count_replies(ads, res)) {
296 d_printf("ads_user_add: User %s already exists\n", argv[0]);
297 goto done;
300 if (opt_container == NULL) {
301 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
304 status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
306 if (!ADS_ERR_OK(status)) {
307 d_printf("Could not add user %s: %s\n", argv[0],
308 ads_errstr(status));
309 goto done;
312 /* if no password is to be set, we're done */
313 if (argc == 1) {
314 d_printf("User %s added\n", argv[0]);
315 rc = 0;
316 goto done;
319 /* try setting the password */
320 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
321 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
322 ads->auth.time_offset);
323 safe_free(upn);
324 if (ADS_ERR_OK(status)) {
325 d_printf("User %s added\n", argv[0]);
326 rc = 0;
327 goto done;
330 /* password didn't set, delete account */
331 d_printf("Could not add user %s. Error setting password %s\n",
332 argv[0], ads_errstr(status));
333 ads_msgfree(ads, res);
334 status=ads_find_user_acct(ads, &res, argv[0]);
335 if (ADS_ERR_OK(status)) {
336 userdn = ads_get_dn(ads, res);
337 ads_del_dn(ads, userdn);
338 ads_memfree(ads, userdn);
341 done:
342 if (res)
343 ads_msgfree(ads, res);
344 ads_destroy(&ads);
345 return rc;
348 static int ads_user_info(int argc, const char **argv)
350 ADS_STRUCT *ads;
351 ADS_STATUS rc;
352 void *res;
353 const char *attrs[] = {"memberOf", NULL};
354 char *searchstring=NULL;
355 char **grouplist;
356 char *escaped_user = escape_ldap_string_alloc(argv[0]);
358 if (argc < 1) {
359 return net_ads_user_usage(argc, argv);
362 if (!(ads = ads_startup())) {
363 return -1;
366 if (!escaped_user) {
367 d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
368 ads_destroy(&ads);
369 return -1;
372 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
373 rc = ads_search(ads, &res, searchstring, attrs);
374 safe_free(searchstring);
376 if (!ADS_ERR_OK(rc)) {
377 d_printf("ads_search: %s\n", ads_errstr(rc));
378 ads_destroy(&ads);
379 return -1;
382 grouplist = ldap_get_values(ads->ld, res, "memberOf");
384 if (grouplist) {
385 int i;
386 char **groupname;
387 for (i=0;grouplist[i];i++) {
388 groupname = ldap_explode_dn(grouplist[i], 1);
389 d_printf("%s\n", groupname[0]);
390 ldap_value_free(groupname);
392 ldap_value_free(grouplist);
395 ads_msgfree(ads, res);
396 ads_destroy(&ads);
397 return 0;
400 static int ads_user_delete(int argc, const char **argv)
402 ADS_STRUCT *ads;
403 ADS_STATUS rc;
404 void *res;
405 char *userdn;
407 if (argc < 1) {
408 return net_ads_user_usage(argc, argv);
411 if (!(ads = ads_startup())) {
412 return -1;
415 rc = ads_find_user_acct(ads, &res, argv[0]);
416 if (!ADS_ERR_OK(rc)) {
417 DEBUG(0, ("User %s does not exist\n", argv[0]));
418 ads_destroy(&ads);
419 return -1;
421 userdn = ads_get_dn(ads, res);
422 ads_msgfree(ads, res);
423 rc = ads_del_dn(ads, userdn);
424 ads_memfree(ads, userdn);
425 if (!ADS_ERR_OK(rc)) {
426 d_printf("User %s deleted\n", argv[0]);
427 ads_destroy(&ads);
428 return 0;
430 d_printf("Error deleting user %s: %s\n", argv[0],
431 ads_errstr(rc));
432 ads_destroy(&ads);
433 return -1;
436 int net_ads_user(int argc, const char **argv)
438 struct functable func[] = {
439 {"ADD", ads_user_add},
440 {"INFO", ads_user_info},
441 {"DELETE", ads_user_delete},
442 {NULL, NULL}
444 ADS_STRUCT *ads;
445 ADS_STATUS rc;
446 const char *shortattrs[] = {"sAMAccountName", NULL};
447 const char *longattrs[] = {"sAMAccountName", "description", NULL};
448 char *disp_fields[2] = {NULL, NULL};
450 if (argc == 0) {
451 if (!(ads = ads_startup())) {
452 return -1;
455 if (opt_long_list_entries)
456 d_printf("\nUser name Comment"\
457 "\n-----------------------------\n");
459 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
460 LDAP_SCOPE_SUBTREE,
461 "(objectclass=user)",
462 opt_long_list_entries ? longattrs :
463 shortattrs, usergrp_display,
464 disp_fields);
465 ads_destroy(&ads);
466 return 0;
469 return net_run_function(argc, argv, func, net_ads_user_usage);
472 static int net_ads_group_usage(int argc, const char **argv)
474 return net_help_group(argc, argv);
477 static int ads_group_add(int argc, const char **argv)
479 ADS_STRUCT *ads;
480 ADS_STATUS status;
481 void *res=NULL;
482 int rc = -1;
484 if (argc < 1) {
485 return net_ads_group_usage(argc, argv);
488 if (!(ads = ads_startup())) {
489 return -1;
492 status = ads_find_user_acct(ads, &res, argv[0]);
494 if (!ADS_ERR_OK(status)) {
495 d_printf("ads_group_add: %s\n", ads_errstr(status));
496 goto done;
499 if (ads_count_replies(ads, res)) {
500 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
501 ads_msgfree(ads, res);
502 goto done;
505 if (opt_container == NULL) {
506 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
509 status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
511 if (ADS_ERR_OK(status)) {
512 d_printf("Group %s added\n", argv[0]);
513 rc = 0;
514 } else {
515 d_printf("Could not add group %s: %s\n", argv[0],
516 ads_errstr(status));
519 done:
520 if (res)
521 ads_msgfree(ads, res);
522 ads_destroy(&ads);
523 return rc;
526 static int ads_group_delete(int argc, const char **argv)
528 ADS_STRUCT *ads;
529 ADS_STATUS rc;
530 void *res;
531 char *groupdn;
533 if (argc < 1) {
534 return net_ads_group_usage(argc, argv);
537 if (!(ads = ads_startup())) {
538 return -1;
541 rc = ads_find_user_acct(ads, &res, argv[0]);
542 if (!ADS_ERR_OK(rc)) {
543 DEBUG(0, ("Group %s does not exist\n", argv[0]));
544 ads_destroy(&ads);
545 return -1;
547 groupdn = ads_get_dn(ads, res);
548 ads_msgfree(ads, res);
549 rc = ads_del_dn(ads, groupdn);
550 ads_memfree(ads, groupdn);
551 if (!ADS_ERR_OK(rc)) {
552 d_printf("Group %s deleted\n", argv[0]);
553 ads_destroy(&ads);
554 return 0;
556 d_printf("Error deleting group %s: %s\n", argv[0],
557 ads_errstr(rc));
558 ads_destroy(&ads);
559 return -1;
562 int net_ads_group(int argc, const char **argv)
564 struct functable func[] = {
565 {"ADD", ads_group_add},
566 {"DELETE", ads_group_delete},
567 {NULL, NULL}
569 ADS_STRUCT *ads;
570 ADS_STATUS rc;
571 const char *shortattrs[] = {"sAMAccountName", NULL};
572 const char *longattrs[] = {"sAMAccountName", "description", NULL};
573 char *disp_fields[2] = {NULL, NULL};
575 if (argc == 0) {
576 if (!(ads = ads_startup())) {
577 return -1;
580 if (opt_long_list_entries)
581 d_printf("\nGroup name Comment"\
582 "\n-----------------------------\n");
583 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
584 LDAP_SCOPE_SUBTREE,
585 "(objectclass=group)",
586 opt_long_list_entries ? longattrs :
587 shortattrs, usergrp_display,
588 disp_fields);
590 ads_destroy(&ads);
591 return 0;
593 return net_run_function(argc, argv, func, net_ads_group_usage);
596 static int net_ads_status(int argc, const char **argv)
598 ADS_STRUCT *ads;
599 ADS_STATUS rc;
600 void *res;
602 if (!(ads = ads_startup())) {
603 return -1;
606 rc = ads_find_machine_acct(ads, &res, global_myname());
607 if (!ADS_ERR_OK(rc)) {
608 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
609 ads_destroy(&ads);
610 return -1;
613 if (ads_count_replies(ads, res) == 0) {
614 d_printf("No machine account for '%s' found\n", global_myname());
615 ads_destroy(&ads);
616 return -1;
619 ads_dump(ads, res);
620 ads_destroy(&ads);
621 return 0;
624 static int net_ads_leave(int argc, const char **argv)
626 ADS_STRUCT *ads = NULL;
627 ADS_STATUS rc;
629 if (!secrets_init()) {
630 DEBUG(1,("Failed to initialise secrets database\n"));
631 return -1;
634 if (!opt_password) {
635 net_use_machine_password();
638 if (!(ads = ads_startup())) {
639 return -1;
642 rc = ads_leave_realm(ads, global_myname());
643 if (!ADS_ERR_OK(rc)) {
644 d_printf("Failed to delete host '%s' from the '%s' realm.\n",
645 global_myname(), ads->config.realm);
646 ads_destroy(&ads);
647 return -1;
650 d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
651 ads_destroy(&ads);
652 return 0;
655 static int net_ads_join_ok(void)
657 ADS_STRUCT *ads = NULL;
659 if (!secrets_init()) {
660 DEBUG(1,("Failed to initialise secrets database\n"));
661 return -1;
664 net_use_machine_password();
666 if (!(ads = ads_startup())) {
667 return -1;
670 ads_destroy(&ads);
671 return 0;
675 check that an existing join is OK
677 int net_ads_testjoin(int argc, const char **argv)
679 use_in_memory_ccache();
681 /* Display success or failure */
682 if (net_ads_join_ok() != 0) {
683 fprintf(stderr,"Join to domain is not valid\n");
684 return -1;
687 printf("Join is OK\n");
688 return 0;
692 join a domain using ADS
694 int net_ads_join(int argc, const char **argv)
696 ADS_STRUCT *ads;
697 ADS_STATUS rc;
698 char *password;
699 char *machine_account = NULL;
700 char *tmp_password;
701 const char *org_unit = NULL;
702 char *dn;
703 void *res;
704 DOM_SID dom_sid;
705 char *ou_str;
706 uint32 sec_channel_type = SEC_CHAN_WKSTA;
707 uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT;
708 const char *short_domain_name = NULL;
709 TALLOC_CTX *ctx = NULL;
711 if (argc > 0) {
712 org_unit = argv[0];
715 if (!secrets_init()) {
716 DEBUG(1,("Failed to initialise secrets database\n"));
717 return -1;
720 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
721 password = strdup(tmp_password);
723 if (!(ads = ads_startup())) {
724 return -1;
727 if (!*lp_realm()) {
728 d_printf("realm must be set in in smb.conf for ADS join to succeed.\n");
729 ads_destroy(&ads);
730 return -1;
733 if (strcmp(ads->config.realm, lp_realm()) != 0) {
734 d_printf("realm of remote server (%s) and realm in smb.conf (%s) DO NOT match. Aborting join\n", ads->config.realm, lp_realm());
735 ads_destroy(&ads);
736 return -1;
739 ou_str = ads_ou_string(ads,org_unit);
740 asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
741 free(ou_str);
743 rc = ads_search_dn(ads, &res, dn, NULL);
744 ads_msgfree(ads, res);
746 if (rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
747 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
748 org_unit, dn);
749 ads_destroy(&ads);
750 return -1;
752 free(dn);
754 if (!ADS_ERR_OK(rc)) {
755 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
756 ads_destroy(&ads);
757 return -1;
760 rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
761 if (!ADS_ERR_OK(rc)) {
762 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
763 ads_destroy(&ads);
764 return -1;
767 rc = ads_domain_sid(ads, &dom_sid);
768 if (!ADS_ERR_OK(rc)) {
769 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
770 ads_destroy(&ads);
771 return -1;
774 if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
775 d_printf("asprintf failed\n");
776 ads_destroy(&ads);
777 return -1;
780 rc = ads_set_machine_password(ads, machine_account, password);
781 if (!ADS_ERR_OK(rc)) {
782 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
783 ads_destroy(&ads);
784 return -1;
787 /* make sure we get the right workgroup */
789 if ( !(ctx = talloc_init("net ads join")) ) {
790 d_printf("talloc_init() failed!\n");
791 ads_destroy(&ads);
792 return -1;
795 rc = ads_workgroup_name(ads, ctx, &short_domain_name);
796 if ( ADS_ERR_OK(rc) ) {
797 if ( !strequal(lp_workgroup(), short_domain_name) ) {
798 d_printf("The workgroup in smb.conf does not match the short\n");
799 d_printf("domain name obtained from the server.\n");
800 d_printf("Using the name [%s] from the server.\n", short_domain_name);
801 d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
803 } else {
804 short_domain_name = lp_workgroup();
807 d_printf("Using short domain name -- %s\n", short_domain_name);
809 /* HACK ALRET! Store the sid and password under bother the lp_workgroup()
810 value from smb.conf and the string returned from the server. The former is
811 neede to bootstrap winbindd's first connection to the DC to get the real
812 short domain name --jerry */
814 if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
815 DEBUG(1,("Failed to save domain sid\n"));
816 ads_destroy(&ads);
817 return -1;
820 if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
821 DEBUG(1,("Failed to save machine password\n"));
822 ads_destroy(&ads);
823 return -1;
826 #ifdef HAVE_KRB5
827 if (!kerberos_derive_salting_principal(machine_account)) {
828 DEBUG(1,("Failed to determine salting principal\n"));
829 ads_destroy(&ads);
830 return -1;
833 if (!kerberos_derive_cifs_salting_principals()) {
834 DEBUG(1,("Failed to determine salting principals\n"));
835 ads_destroy(&ads);
836 return -1;
838 #endif
840 if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) {
841 DEBUG(1,("Failed to save domain sid\n"));
842 ads_destroy(&ads);
843 return -1;
846 if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) {
847 DEBUG(1,("Failed to save machine password\n"));
848 ads_destroy(&ads);
849 return -1;
852 /* Now build the keytab, using the same ADS connection */
853 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
854 DEBUG(1,("Error creating host keytab!\n"));
857 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
859 SAFE_FREE(password);
860 SAFE_FREE(machine_account);
861 if ( ctx ) {
862 talloc_destroy(ctx);
864 ads_destroy(&ads);
865 return 0;
868 int net_ads_printer_usage(int argc, const char **argv)
870 d_printf(
871 "\nnet ads printer search <printer>"
872 "\n\tsearch for a printer in the directory\n"
873 "\nnet ads printer info <printer> <server>"
874 "\n\tlookup info in directory for printer on server"
875 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
876 "\nnet ads printer publish <printername>"
877 "\n\tpublish printer in directory"
878 "\n\t(note: printer name is required)\n"
879 "\nnet ads printer remove <printername>"
880 "\n\tremove printer from directory"
881 "\n\t(note: printer name is required)\n");
882 return -1;
885 static int net_ads_printer_search(int argc, const char **argv)
887 ADS_STRUCT *ads;
888 ADS_STATUS rc;
889 void *res = NULL;
891 if (!(ads = ads_startup())) {
892 return -1;
895 rc = ads_find_printers(ads, &res);
897 if (!ADS_ERR_OK(rc)) {
898 d_printf("ads_find_printer: %s\n", ads_errstr(rc));
899 ads_msgfree(ads, res);
900 ads_destroy(&ads);
901 return -1;
904 if (ads_count_replies(ads, res) == 0) {
905 d_printf("No results found\n");
906 ads_msgfree(ads, res);
907 ads_destroy(&ads);
908 return -1;
911 ads_dump(ads, res);
912 ads_msgfree(ads, res);
913 ads_destroy(&ads);
914 return 0;
917 static int net_ads_printer_info(int argc, const char **argv)
919 ADS_STRUCT *ads;
920 ADS_STATUS rc;
921 const char *servername, *printername;
922 void *res = NULL;
924 if (!(ads = ads_startup())) {
925 return -1;
928 if (argc > 0) {
929 printername = argv[0];
930 } else {
931 printername = "*";
934 if (argc > 1) {
935 servername = argv[1];
936 } else {
937 servername = global_myname();
940 rc = ads_find_printer_on_server(ads, &res, printername, servername);
942 if (!ADS_ERR_OK(rc)) {
943 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
944 ads_msgfree(ads, res);
945 ads_destroy(&ads);
946 return -1;
949 if (ads_count_replies(ads, res) == 0) {
950 d_printf("Printer '%s' not found\n", printername);
951 ads_msgfree(ads, res);
952 ads_destroy(&ads);
953 return -1;
956 ads_dump(ads, res);
957 ads_msgfree(ads, res);
958 ads_destroy(&ads);
960 return 0;
963 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
965 return;
968 static int net_ads_printer_publish(int argc, const char **argv)
970 ADS_STRUCT *ads;
971 ADS_STATUS rc;
972 const char *servername, *printername;
973 struct cli_state *cli;
974 struct in_addr server_ip;
975 NTSTATUS nt_status;
976 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
977 ADS_MODLIST mods = ads_init_mods(mem_ctx);
978 char *prt_dn, *srv_dn, **srv_cn;
979 void *res = NULL;
981 if (!(ads = ads_startup())) {
982 return -1;
985 if (argc < 1) {
986 return net_ads_printer_usage(argc, argv);
989 printername = argv[0];
991 if (argc == 2) {
992 servername = argv[1];
993 } else {
994 servername = global_myname();
997 /* Get printer data from SPOOLSS */
999 resolve_name(servername, &server_ip, 0x20);
1001 nt_status = cli_full_connection(&cli, global_myname(), servername,
1002 &server_ip, 0,
1003 "IPC$", "IPC",
1004 opt_user_name, opt_workgroup,
1005 opt_password ? opt_password : "",
1006 CLI_FULL_CONNECTION_USE_KERBEROS,
1007 Undefined, NULL);
1009 if (NT_STATUS_IS_ERR(nt_status)) {
1010 d_printf("Unable to open a connnection to %s to obtain data "
1011 "for %s\n", servername, printername);
1012 ads_destroy(&ads);
1013 return -1;
1016 /* Publish on AD server */
1018 ads_find_machine_acct(ads, &res, servername);
1020 if (ads_count_replies(ads, res) == 0) {
1021 d_printf("Could not find machine account for server %s\n",
1022 servername);
1023 ads_destroy(&ads);
1024 return -1;
1027 srv_dn = ldap_get_dn(ads->ld, res);
1028 srv_cn = ldap_explode_dn(srv_dn, 1);
1030 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
1032 cli_nt_session_open(cli, PI_SPOOLSS);
1033 get_remote_printer_publishing_data(cli, mem_ctx, &mods, printername);
1035 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1036 if (!ADS_ERR_OK(rc)) {
1037 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
1038 ads_destroy(&ads);
1039 return -1;
1042 d_printf("published printer\n");
1043 ads_destroy(&ads);
1045 return 0;
1048 static int net_ads_printer_remove(int argc, const char **argv)
1050 ADS_STRUCT *ads;
1051 ADS_STATUS rc;
1052 const char *servername;
1053 char *prt_dn;
1054 void *res = NULL;
1056 if (!(ads = ads_startup())) {
1057 return -1;
1060 if (argc < 1) {
1061 return net_ads_printer_usage(argc, argv);
1064 if (argc > 1) {
1065 servername = argv[1];
1066 } else {
1067 servername = global_myname();
1070 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1072 if (!ADS_ERR_OK(rc)) {
1073 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
1074 ads_msgfree(ads, res);
1075 ads_destroy(&ads);
1076 return -1;
1079 if (ads_count_replies(ads, res) == 0) {
1080 d_printf("Printer '%s' not found\n", argv[1]);
1081 ads_msgfree(ads, res);
1082 ads_destroy(&ads);
1083 return -1;
1086 prt_dn = ads_get_dn(ads, res);
1087 ads_msgfree(ads, res);
1088 rc = ads_del_dn(ads, prt_dn);
1089 ads_memfree(ads, prt_dn);
1091 if (!ADS_ERR_OK(rc)) {
1092 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
1093 ads_destroy(&ads);
1094 return -1;
1097 ads_destroy(&ads);
1098 return 0;
1101 static int net_ads_printer(int argc, const char **argv)
1103 struct functable func[] = {
1104 {"SEARCH", net_ads_printer_search},
1105 {"INFO", net_ads_printer_info},
1106 {"PUBLISH", net_ads_printer_publish},
1107 {"REMOVE", net_ads_printer_remove},
1108 {NULL, NULL}
1111 return net_run_function(argc, argv, func, net_ads_printer_usage);
1115 static int net_ads_password(int argc, const char **argv)
1117 ADS_STRUCT *ads;
1118 const char *auth_principal = opt_user_name;
1119 const char *auth_password = opt_password;
1120 char *realm = NULL;
1121 char *new_password = NULL;
1122 char *c, *prompt;
1123 const char *user;
1124 ADS_STATUS ret;
1126 if (opt_user_name == NULL || opt_password == NULL) {
1127 d_printf("You must supply an administrator username/password\n");
1128 return -1;
1131 if (argc < 1) {
1132 d_printf("ERROR: You must say which username to change password for\n");
1133 return -1;
1136 user = argv[0];
1137 if (!strchr_m(user, '@')) {
1138 asprintf(&c, "%s@%s", argv[0], lp_realm());
1139 user = c;
1142 use_in_memory_ccache();
1143 c = strchr_m(auth_principal, '@');
1144 if (c) {
1145 realm = ++c;
1146 } else {
1147 realm = lp_realm();
1150 /* use the realm so we can eventually change passwords for users
1151 in realms other than default */
1152 if (!(ads = ads_init(realm, NULL, NULL))) {
1153 return -1;
1156 /* we don't actually need a full connect, but it's the easy way to
1157 fill in the KDC's addresss */
1158 ads_connect(ads);
1160 if (!ads || !ads->config.realm) {
1161 d_printf("Didn't find the kerberos server!\n");
1162 return -1;
1165 if (argv[1]) {
1166 new_password = (char *)argv[1];
1167 } else {
1168 asprintf(&prompt, "Enter new password for %s:", user);
1169 new_password = getpass(prompt);
1170 free(prompt);
1173 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1174 auth_password, user, new_password, ads->auth.time_offset);
1175 if (!ADS_ERR_OK(ret)) {
1176 d_printf("Password change failed :-( ...\n");
1177 ads_destroy(&ads);
1178 return -1;
1181 d_printf("Password change for %s completed.\n", user);
1182 ads_destroy(&ads);
1184 return 0;
1187 int net_ads_changetrustpw(int argc, const char **argv)
1189 ADS_STRUCT *ads;
1190 char *host_principal;
1191 fstring my_name;
1192 ADS_STATUS ret;
1194 if (!secrets_init()) {
1195 DEBUG(1,("Failed to initialise secrets database\n"));
1196 return -1;
1199 net_use_machine_password();
1201 use_in_memory_ccache();
1203 if (!(ads = ads_startup())) {
1204 return -1;
1207 fstrcpy(my_name, global_myname());
1208 strlower_m(my_name);
1209 asprintf(&host_principal, "%s@%s", my_name, ads->config.realm);
1210 d_printf("Changing password for principal: HOST/%s\n", host_principal);
1212 ret = ads_change_trust_account_password(ads, host_principal);
1214 if (!ADS_ERR_OK(ret)) {
1215 d_printf("Password change failed :-( ...\n");
1216 ads_destroy(&ads);
1217 SAFE_FREE(host_principal);
1218 return -1;
1221 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
1223 if (lp_use_kerberos_keytab()) {
1224 d_printf("Attempting to update system keytab with new password.\n");
1225 if (ads_keytab_create_default(ads)) {
1226 d_printf("Failed to update system keytab.\n");
1230 ads_destroy(&ads);
1231 SAFE_FREE(host_principal);
1233 return 0;
1237 help for net ads search
1239 static int net_ads_search_usage(int argc, const char **argv)
1241 d_printf(
1242 "\nnet ads search <expression> <attributes...>\n"\
1243 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1244 "The expression is a standard LDAP search expression, and the\n"\
1245 "attributes are a list of LDAP fields to show in the results\n\n"\
1246 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1248 net_common_flags_usage(argc, argv);
1249 return -1;
1254 general ADS search function. Useful in diagnosing problems in ADS
1256 static int net_ads_search(int argc, const char **argv)
1258 ADS_STRUCT *ads;
1259 ADS_STATUS rc;
1260 const char *ldap_exp;
1261 const char **attrs;
1262 void *res = NULL;
1264 if (argc < 1) {
1265 return net_ads_search_usage(argc, argv);
1268 if (!(ads = ads_startup())) {
1269 return -1;
1272 ldap_exp = argv[0];
1273 attrs = (argv + 1);
1275 rc = ads_do_search_all(ads, ads->config.bind_path,
1276 LDAP_SCOPE_SUBTREE,
1277 ldap_exp, attrs, &res);
1278 if (!ADS_ERR_OK(rc)) {
1279 d_printf("search failed: %s\n", ads_errstr(rc));
1280 ads_destroy(&ads);
1281 return -1;
1284 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1286 /* dump the results */
1287 ads_dump(ads, res);
1289 ads_msgfree(ads, res);
1290 ads_destroy(&ads);
1292 return 0;
1297 help for net ads search
1299 static int net_ads_dn_usage(int argc, const char **argv)
1301 d_printf(
1302 "\nnet ads dn <dn> <attributes...>\n"\
1303 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1304 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1305 "to show in the results\n\n"\
1306 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1308 net_common_flags_usage(argc, argv);
1309 return -1;
1314 general ADS search function. Useful in diagnosing problems in ADS
1316 static int net_ads_dn(int argc, const char **argv)
1318 ADS_STRUCT *ads;
1319 ADS_STATUS rc;
1320 const char *dn;
1321 const char **attrs;
1322 void *res = NULL;
1324 if (argc < 1) {
1325 return net_ads_dn_usage(argc, argv);
1328 if (!(ads = ads_startup())) {
1329 return -1;
1332 dn = argv[0];
1333 attrs = (argv + 1);
1335 rc = ads_do_search_all(ads, dn,
1336 LDAP_SCOPE_BASE,
1337 "(objectclass=*)", attrs, &res);
1338 if (!ADS_ERR_OK(rc)) {
1339 d_printf("search failed: %s\n", ads_errstr(rc));
1340 ads_destroy(&ads);
1341 return -1;
1344 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1346 /* dump the results */
1347 ads_dump(ads, res);
1349 ads_msgfree(ads, res);
1350 ads_destroy(&ads);
1352 return 0;
1355 static int net_ads_keytab_usage(int argc, const char **argv)
1357 d_printf(
1358 "net ads keytab <COMMAND>\n"\
1359 "<COMMAND> can be either:\n"\
1360 " CREATE Creates a fresh keytab\n"\
1361 " ADD Adds new service principal\n"\
1362 " FLUSH Flushes out all keytab entries\n"\
1363 " HELP Prints this help message\n"\
1364 "The ADD command will take arguments, the other commands\n"\
1365 "will not take any arguments. The arguments given to ADD\n"\
1366 "should be a list of principals to add. For example, \n"\
1367 " net ads keytab add srv1 srv2\n"\
1368 "will add principals for the services srv1 and srv2 to the\n"\
1369 "system's keytab.\n"\
1370 "\n"
1372 return -1;
1375 static int net_ads_keytab_flush(int argc, const char **argv)
1377 int ret;
1378 ADS_STRUCT *ads;
1380 if (!(ads = ads_startup())) {
1381 return -1;
1383 ret = ads_keytab_flush(ads);
1384 ads_destroy(&ads);
1385 return ret;
1388 static int net_ads_keytab_add(int argc, const char **argv)
1390 int i;
1391 int ret = 0;
1392 ADS_STRUCT *ads;
1394 d_printf("Processing principals to add...\n");
1395 if (!(ads = ads_startup())) {
1396 return -1;
1398 for (i = 0; i < argc; i++) {
1399 ret |= ads_keytab_add_entry(ads, argv[i]);
1401 ads_destroy(&ads);
1402 return ret;
1405 static int net_ads_keytab_create(int argc, const char **argv)
1407 ADS_STRUCT *ads;
1408 int ret;
1410 if (!(ads = ads_startup())) {
1411 return -1;
1413 ret = ads_keytab_create_default(ads);
1414 ads_destroy(&ads);
1415 return ret;
1418 int net_ads_keytab(int argc, const char **argv)
1420 struct functable func[] = {
1421 {"CREATE", net_ads_keytab_create},
1422 {"ADD", net_ads_keytab_add},
1423 {"FLUSH", net_ads_keytab_flush},
1424 {"HELP", net_ads_keytab_usage},
1425 {NULL, NULL}
1428 if (!lp_use_kerberos_keytab()) {
1429 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
1430 use keytab functions.\n");
1433 return net_run_function(argc, argv, func, net_ads_keytab_usage);
1436 int net_ads_help(int argc, const char **argv)
1438 struct functable func[] = {
1439 {"USER", net_ads_user_usage},
1440 {"GROUP", net_ads_group_usage},
1441 {"PRINTER", net_ads_printer_usage},
1442 {"SEARCH", net_ads_search_usage},
1443 #if 0
1444 {"INFO", net_ads_info},
1445 {"JOIN", net_ads_join},
1446 {"LEAVE", net_ads_leave},
1447 {"STATUS", net_ads_status},
1448 {"PASSWORD", net_ads_password},
1449 {"CHANGETRUSTPW", net_ads_changetrustpw},
1450 #endif
1451 {NULL, NULL}
1454 return net_run_function(argc, argv, func, net_ads_usage);
1457 int net_ads(int argc, const char **argv)
1459 struct functable func[] = {
1460 {"INFO", net_ads_info},
1461 {"JOIN", net_ads_join},
1462 {"TESTJOIN", net_ads_testjoin},
1463 {"LEAVE", net_ads_leave},
1464 {"STATUS", net_ads_status},
1465 {"USER", net_ads_user},
1466 {"GROUP", net_ads_group},
1467 {"PASSWORD", net_ads_password},
1468 {"CHANGETRUSTPW", net_ads_changetrustpw},
1469 {"PRINTER", net_ads_printer},
1470 {"SEARCH", net_ads_search},
1471 {"DN", net_ads_dn},
1472 {"WORKGROUP", net_ads_workgroup},
1473 {"LOOKUP", net_ads_lookup},
1474 {"KEYTAB", net_ads_keytab},
1475 {"HELP", net_ads_help},
1476 {NULL, NULL}
1479 return net_run_function(argc, argv, func, net_ads_usage);
1482 #else
1484 static int net_ads_noads(void)
1486 d_printf("ADS support not compiled in\n");
1487 return -1;
1490 int net_ads_keytab(int argc, const char **argv)
1492 return net_ads_noads();
1495 int net_ads_usage(int argc, const char **argv)
1497 return net_ads_noads();
1500 int net_ads_help(int argc, const char **argv)
1502 return net_ads_noads();
1505 int net_ads_changetrustpw(int argc, const char **argv)
1507 return net_ads_noads();
1510 int net_ads_join(int argc, const char **argv)
1512 return net_ads_noads();
1515 int net_ads_user(int argc, const char **argv)
1517 return net_ads_noads();
1520 int net_ads_group(int argc, const char **argv)
1522 return net_ads_noads();
1525 /* this one shouldn't display a message */
1526 int net_ads_check(void)
1528 return -1;
1531 int net_ads(int argc, const char **argv)
1533 return net_ads_usage(argc, argv);
1536 #endif