r3220: merging current 3.0 code to release branch
[Samba.git] / source / utils / net_ads.c
blob19311cde6547ded8f650b258a2d9a31443269991
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(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 if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) {
827 DEBUG(1,("Failed to save domain sid\n"));
828 ads_destroy(&ads);
829 return -1;
832 if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) {
833 DEBUG(1,("Failed to save machine password\n"));
834 ads_destroy(&ads);
835 return -1;
838 /* Now build the keytab, using the same ADS connection */
839 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
840 DEBUG(1,("Error creating host keytab!\n"));
843 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
845 SAFE_FREE(password);
846 SAFE_FREE(machine_account);
847 if ( ctx ) {
848 talloc_destroy(ctx);
850 ads_destroy(&ads);
851 return 0;
854 int net_ads_printer_usage(int argc, const char **argv)
856 d_printf(
857 "\nnet ads printer search <printer>"
858 "\n\tsearch for a printer in the directory\n"
859 "\nnet ads printer info <printer> <server>"
860 "\n\tlookup info in directory for printer on server"
861 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
862 "\nnet ads printer publish <printername>"
863 "\n\tpublish printer in directory"
864 "\n\t(note: printer name is required)\n"
865 "\nnet ads printer remove <printername>"
866 "\n\tremove printer from directory"
867 "\n\t(note: printer name is required)\n");
868 return -1;
871 static int net_ads_printer_search(int argc, const char **argv)
873 ADS_STRUCT *ads;
874 ADS_STATUS rc;
875 void *res = NULL;
877 if (!(ads = ads_startup())) {
878 return -1;
881 rc = ads_find_printers(ads, &res);
883 if (!ADS_ERR_OK(rc)) {
884 d_printf("ads_find_printer: %s\n", ads_errstr(rc));
885 ads_msgfree(ads, res);
886 ads_destroy(&ads);
887 return -1;
890 if (ads_count_replies(ads, res) == 0) {
891 d_printf("No results found\n");
892 ads_msgfree(ads, res);
893 ads_destroy(&ads);
894 return -1;
897 ads_dump(ads, res);
898 ads_msgfree(ads, res);
899 ads_destroy(&ads);
900 return 0;
903 static int net_ads_printer_info(int argc, const char **argv)
905 ADS_STRUCT *ads;
906 ADS_STATUS rc;
907 const char *servername, *printername;
908 void *res = NULL;
910 if (!(ads = ads_startup())) {
911 return -1;
914 if (argc > 0) {
915 printername = argv[0];
916 } else {
917 printername = "*";
920 if (argc > 1) {
921 servername = argv[1];
922 } else {
923 servername = global_myname();
926 rc = ads_find_printer_on_server(ads, &res, printername, servername);
928 if (!ADS_ERR_OK(rc)) {
929 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
930 ads_msgfree(ads, res);
931 ads_destroy(&ads);
932 return -1;
935 if (ads_count_replies(ads, res) == 0) {
936 d_printf("Printer '%s' not found\n", printername);
937 ads_msgfree(ads, res);
938 ads_destroy(&ads);
939 return -1;
942 ads_dump(ads, res);
943 ads_msgfree(ads, res);
944 ads_destroy(&ads);
946 return 0;
949 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
951 return;
954 static int net_ads_printer_publish(int argc, const char **argv)
956 ADS_STRUCT *ads;
957 ADS_STATUS rc;
958 const char *servername, *printername;
959 struct cli_state *cli;
960 struct in_addr server_ip;
961 NTSTATUS nt_status;
962 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
963 ADS_MODLIST mods = ads_init_mods(mem_ctx);
964 char *prt_dn, *srv_dn, **srv_cn;
965 void *res = NULL;
967 if (!(ads = ads_startup())) {
968 return -1;
971 if (argc < 1) {
972 return net_ads_printer_usage(argc, argv);
975 printername = argv[0];
977 if (argc == 2) {
978 servername = argv[1];
979 } else {
980 servername = global_myname();
983 /* Get printer data from SPOOLSS */
985 resolve_name(servername, &server_ip, 0x20);
987 nt_status = cli_full_connection(&cli, global_myname(), servername,
988 &server_ip, 0,
989 "IPC$", "IPC",
990 opt_user_name, opt_workgroup,
991 opt_password ? opt_password : "",
992 CLI_FULL_CONNECTION_USE_KERBEROS,
993 Undefined, NULL);
995 if (NT_STATUS_IS_ERR(nt_status)) {
996 d_printf("Unable to open a connnection to %s to obtain data "
997 "for %s\n", servername, printername);
998 ads_destroy(&ads);
999 return -1;
1002 /* Publish on AD server */
1004 ads_find_machine_acct(ads, &res, servername);
1006 if (ads_count_replies(ads, res) == 0) {
1007 d_printf("Could not find machine account for server %s\n",
1008 servername);
1009 ads_destroy(&ads);
1010 return -1;
1013 srv_dn = ldap_get_dn(ads->ld, res);
1014 srv_cn = ldap_explode_dn(srv_dn, 1);
1016 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
1018 cli_nt_session_open(cli, PI_SPOOLSS);
1019 get_remote_printer_publishing_data(cli, mem_ctx, &mods, printername);
1021 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1022 if (!ADS_ERR_OK(rc)) {
1023 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
1024 ads_destroy(&ads);
1025 return -1;
1028 d_printf("published printer\n");
1029 ads_destroy(&ads);
1031 return 0;
1034 static int net_ads_printer_remove(int argc, const char **argv)
1036 ADS_STRUCT *ads;
1037 ADS_STATUS rc;
1038 const char *servername;
1039 char *prt_dn;
1040 void *res = NULL;
1042 if (!(ads = ads_startup())) {
1043 return -1;
1046 if (argc < 1) {
1047 return net_ads_printer_usage(argc, argv);
1050 if (argc > 1) {
1051 servername = argv[1];
1052 } else {
1053 servername = global_myname();
1056 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1058 if (!ADS_ERR_OK(rc)) {
1059 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
1060 ads_msgfree(ads, res);
1061 ads_destroy(&ads);
1062 return -1;
1065 if (ads_count_replies(ads, res) == 0) {
1066 d_printf("Printer '%s' not found\n", argv[1]);
1067 ads_msgfree(ads, res);
1068 ads_destroy(&ads);
1069 return -1;
1072 prt_dn = ads_get_dn(ads, res);
1073 ads_msgfree(ads, res);
1074 rc = ads_del_dn(ads, prt_dn);
1075 ads_memfree(ads, prt_dn);
1077 if (!ADS_ERR_OK(rc)) {
1078 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
1079 ads_destroy(&ads);
1080 return -1;
1083 ads_destroy(&ads);
1084 return 0;
1087 static int net_ads_printer(int argc, const char **argv)
1089 struct functable func[] = {
1090 {"SEARCH", net_ads_printer_search},
1091 {"INFO", net_ads_printer_info},
1092 {"PUBLISH", net_ads_printer_publish},
1093 {"REMOVE", net_ads_printer_remove},
1094 {NULL, NULL}
1097 return net_run_function(argc, argv, func, net_ads_printer_usage);
1101 static int net_ads_password(int argc, const char **argv)
1103 ADS_STRUCT *ads;
1104 const char *auth_principal = opt_user_name;
1105 const char *auth_password = opt_password;
1106 char *realm = NULL;
1107 char *new_password = NULL;
1108 char *c, *prompt;
1109 const char *user;
1110 ADS_STATUS ret;
1112 if (opt_user_name == NULL || opt_password == NULL) {
1113 d_printf("You must supply an administrator username/password\n");
1114 return -1;
1117 if (argc < 1) {
1118 d_printf("ERROR: You must say which username to change password for\n");
1119 return -1;
1122 user = argv[0];
1123 if (!strchr_m(user, '@')) {
1124 asprintf(&c, "%s@%s", argv[0], lp_realm());
1125 user = c;
1128 use_in_memory_ccache();
1129 c = strchr(auth_principal, '@');
1130 if (c) {
1131 realm = ++c;
1132 } else {
1133 realm = lp_realm();
1136 /* use the realm so we can eventually change passwords for users
1137 in realms other than default */
1138 if (!(ads = ads_init(realm, NULL, NULL))) {
1139 return -1;
1142 /* we don't actually need a full connect, but it's the easy way to
1143 fill in the KDC's addresss */
1144 ads_connect(ads);
1146 if (!ads || !ads->config.realm) {
1147 d_printf("Didn't find the kerberos server!\n");
1148 return -1;
1151 if (argv[1]) {
1152 new_password = (char *)argv[1];
1153 } else {
1154 asprintf(&prompt, "Enter new password for %s:", user);
1155 new_password = getpass(prompt);
1156 free(prompt);
1159 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1160 auth_password, user, new_password, ads->auth.time_offset);
1161 if (!ADS_ERR_OK(ret)) {
1162 d_printf("Password change failed :-( ...\n");
1163 ads_destroy(&ads);
1164 return -1;
1167 d_printf("Password change for %s completed.\n", user);
1168 ads_destroy(&ads);
1170 return 0;
1173 int net_ads_changetrustpw(int argc, const char **argv)
1175 ADS_STRUCT *ads;
1176 char *host_principal;
1177 fstring my_name;
1178 ADS_STATUS ret;
1180 if (!secrets_init()) {
1181 DEBUG(1,("Failed to initialise secrets database\n"));
1182 return -1;
1185 net_use_machine_password();
1187 use_in_memory_ccache();
1189 if (!(ads = ads_startup())) {
1190 return -1;
1193 fstrcpy(my_name, global_myname());
1194 strlower_m(my_name);
1195 asprintf(&host_principal, "%s@%s", my_name, ads->config.realm);
1196 d_printf("Changing password for principal: HOST/%s\n", host_principal);
1198 ret = ads_change_trust_account_password(ads, host_principal);
1200 if (!ADS_ERR_OK(ret)) {
1201 d_printf("Password change failed :-( ...\n");
1202 ads_destroy(&ads);
1203 SAFE_FREE(host_principal);
1204 return -1;
1207 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
1209 if (lp_use_kerberos_keytab()) {
1210 d_printf("Attempting to update system keytab with new password.\n");
1211 if (ads_keytab_create_default(ads)) {
1212 d_printf("Failed to update system keytab.\n");
1216 ads_destroy(&ads);
1217 SAFE_FREE(host_principal);
1219 return 0;
1223 help for net ads search
1225 static int net_ads_search_usage(int argc, const char **argv)
1227 d_printf(
1228 "\nnet ads search <expression> <attributes...>\n"\
1229 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1230 "The expression is a standard LDAP search expression, and the\n"\
1231 "attributes are a list of LDAP fields to show in the results\n\n"\
1232 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1234 net_common_flags_usage(argc, argv);
1235 return -1;
1240 general ADS search function. Useful in diagnosing problems in ADS
1242 static int net_ads_search(int argc, const char **argv)
1244 ADS_STRUCT *ads;
1245 ADS_STATUS rc;
1246 const char *ldap_exp;
1247 const char **attrs;
1248 void *res = NULL;
1250 if (argc < 1) {
1251 return net_ads_search_usage(argc, argv);
1254 if (!(ads = ads_startup())) {
1255 return -1;
1258 ldap_exp = argv[0];
1259 attrs = (argv + 1);
1261 rc = ads_do_search_all(ads, ads->config.bind_path,
1262 LDAP_SCOPE_SUBTREE,
1263 ldap_exp, attrs, &res);
1264 if (!ADS_ERR_OK(rc)) {
1265 d_printf("search failed: %s\n", ads_errstr(rc));
1266 ads_destroy(&ads);
1267 return -1;
1270 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1272 /* dump the results */
1273 ads_dump(ads, res);
1275 ads_msgfree(ads, res);
1276 ads_destroy(&ads);
1278 return 0;
1283 help for net ads search
1285 static int net_ads_dn_usage(int argc, const char **argv)
1287 d_printf(
1288 "\nnet ads dn <dn> <attributes...>\n"\
1289 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1290 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1291 "to show in the results\n\n"\
1292 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1294 net_common_flags_usage(argc, argv);
1295 return -1;
1300 general ADS search function. Useful in diagnosing problems in ADS
1302 static int net_ads_dn(int argc, const char **argv)
1304 ADS_STRUCT *ads;
1305 ADS_STATUS rc;
1306 const char *dn;
1307 const char **attrs;
1308 void *res = NULL;
1310 if (argc < 1) {
1311 return net_ads_dn_usage(argc, argv);
1314 if (!(ads = ads_startup())) {
1315 return -1;
1318 dn = argv[0];
1319 attrs = (argv + 1);
1321 rc = ads_do_search_all(ads, dn,
1322 LDAP_SCOPE_BASE,
1323 "(objectclass=*)", attrs, &res);
1324 if (!ADS_ERR_OK(rc)) {
1325 d_printf("search failed: %s\n", ads_errstr(rc));
1326 ads_destroy(&ads);
1327 return -1;
1330 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1332 /* dump the results */
1333 ads_dump(ads, res);
1335 ads_msgfree(ads, res);
1336 ads_destroy(&ads);
1338 return 0;
1341 static int net_ads_keytab_usage(int argc, const char **argv)
1343 d_printf(
1344 "net ads keytab <COMMAND>\n"\
1345 "<COMMAND> can be either:\n"\
1346 " CREATE Creates a fresh keytab\n"\
1347 " ADD Adds new service principal\n"\
1348 " FLUSH Flushes out all keytab entries\n"\
1349 " HELP Prints this help message\n"\
1350 "The ADD command will take arguments, the other commands\n"\
1351 "will not take any arguments. The arguments given to ADD\n"\
1352 "should be a list of principals to add. For example, \n"\
1353 " net ads keytab add srv1 srv2\n"\
1354 "will add principals for the services srv1 and srv2 to the\n"\
1355 "system's keytab.\n"\
1356 "\n"
1358 return -1;
1361 static int net_ads_keytab_flush(int argc, const char **argv)
1363 int ret;
1364 ADS_STRUCT *ads;
1366 if (!(ads = ads_startup())) {
1367 return -1;
1369 ret = ads_keytab_flush(ads);
1370 ads_destroy(&ads);
1371 return ret;
1374 static int net_ads_keytab_add(int argc, const char **argv)
1376 int i;
1377 int ret = 0;
1378 ADS_STRUCT *ads;
1380 d_printf("Processing principals to add...\n");
1381 if (!(ads = ads_startup())) {
1382 return -1;
1384 for (i = 0; i < argc; i++) {
1385 ret |= ads_keytab_add_entry(ads, argv[i]);
1387 ads_destroy(&ads);
1388 return ret;
1391 static int net_ads_keytab_create(int argc, const char **argv)
1393 ADS_STRUCT *ads;
1394 int ret;
1396 if (!(ads = ads_startup())) {
1397 return -1;
1399 ret = ads_keytab_create_default(ads);
1400 ads_destroy(&ads);
1401 return ret;
1404 int net_ads_keytab(int argc, const char **argv)
1406 struct functable func[] = {
1407 {"CREATE", net_ads_keytab_create},
1408 {"ADD", net_ads_keytab_add},
1409 {"FLUSH", net_ads_keytab_flush},
1410 {"HELP", net_ads_keytab_usage},
1411 {NULL, NULL}
1414 if (!lp_use_kerberos_keytab()) {
1415 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
1416 use keytab functions.\n");
1419 return net_run_function(argc, argv, func, net_ads_keytab_usage);
1422 int net_ads_help(int argc, const char **argv)
1424 struct functable func[] = {
1425 {"USER", net_ads_user_usage},
1426 {"GROUP", net_ads_group_usage},
1427 {"PRINTER", net_ads_printer_usage},
1428 {"SEARCH", net_ads_search_usage},
1429 #if 0
1430 {"INFO", net_ads_info},
1431 {"JOIN", net_ads_join},
1432 {"LEAVE", net_ads_leave},
1433 {"STATUS", net_ads_status},
1434 {"PASSWORD", net_ads_password},
1435 {"CHANGETRUSTPW", net_ads_changetrustpw},
1436 #endif
1437 {NULL, NULL}
1440 return net_run_function(argc, argv, func, net_ads_usage);
1443 int net_ads(int argc, const char **argv)
1445 struct functable func[] = {
1446 {"INFO", net_ads_info},
1447 {"JOIN", net_ads_join},
1448 {"TESTJOIN", net_ads_testjoin},
1449 {"LEAVE", net_ads_leave},
1450 {"STATUS", net_ads_status},
1451 {"USER", net_ads_user},
1452 {"GROUP", net_ads_group},
1453 {"PASSWORD", net_ads_password},
1454 {"CHANGETRUSTPW", net_ads_changetrustpw},
1455 {"PRINTER", net_ads_printer},
1456 {"SEARCH", net_ads_search},
1457 {"DN", net_ads_dn},
1458 {"WORKGROUP", net_ads_workgroup},
1459 {"LOOKUP", net_ads_lookup},
1460 {"KEYTAB", net_ads_keytab},
1461 {"HELP", net_ads_help},
1462 {NULL, NULL}
1465 return net_run_function(argc, argv, func, net_ads_usage);
1468 #else
1470 static int net_ads_noads(void)
1472 d_printf("ADS support not compiled in\n");
1473 return -1;
1476 int net_ads_keytab(int argc, const char **argv)
1478 return net_ads_noads();
1481 int net_ads_usage(int argc, const char **argv)
1483 return net_ads_noads();
1486 int net_ads_help(int argc, const char **argv)
1488 return net_ads_noads();
1491 int net_ads_changetrustpw(int argc, const char **argv)
1493 return net_ads_noads();
1496 int net_ads_join(int argc, const char **argv)
1498 return net_ads_noads();
1501 int net_ads_user(int argc, const char **argv)
1503 return net_ads_noads();
1506 int net_ads_group(int argc, const char **argv)
1508 return net_ads_noads();
1511 /* this one shouldn't display a message */
1512 int net_ads_check(void)
1514 return -1;
1517 int net_ads(int argc, const char **argv)
1519 return net_ads_usage(argc, argv);
1522 #endif