r1400: final heimdal fixes from 3.0
[Samba.git] / source / utils / net_ads.c
blob7b8ace85b6248f51c3e2028a019875e7fda6b4a9
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 || !ads->config.realm) {
81 d_printf("Didn't find the cldap server!\n");
82 return -1;
85 return ads_cldap_netlogon(ads);
90 static int net_ads_info(int argc, const char **argv)
92 ADS_STRUCT *ads;
94 ads = ads_init(NULL, opt_target_workgroup, opt_host);
96 if (ads) {
97 ads->auth.flags |= ADS_AUTH_NO_BIND;
100 ads_connect(ads);
102 if (!ads || !ads->config.realm) {
103 d_printf("Didn't find the ldap server!\n");
104 return -1;
107 d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
108 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
109 d_printf("Realm: %s\n", ads->config.realm);
110 d_printf("Bind Path: %s\n", ads->config.bind_path);
111 d_printf("LDAP port: %d\n", ads->ldap_port);
112 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
114 d_printf("KDC server: %s\n", ads->auth.kdc_server );
115 d_printf("Server time offset: %d\n", ads->auth.time_offset );
117 return 0;
120 static void use_in_memory_ccache(void) {
121 /* Use in-memory credentials cache so we do not interfere with
122 * existing credentials */
123 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
126 static ADS_STRUCT *ads_startup(void)
128 ADS_STRUCT *ads;
129 ADS_STATUS status;
130 BOOL need_password = False;
131 BOOL second_time = False;
132 char *cp;
134 /* lp_realm() should be handled by a command line param,
135 However, the join requires that realm be set in smb.conf
136 and compares our realm with the remote server's so this is
137 ok until someone needs more flexibility */
139 ads = ads_init(lp_realm(), opt_target_workgroup, opt_host);
141 if (!opt_user_name) {
142 opt_user_name = "administrator";
145 if (opt_user_specified) {
146 need_password = True;
149 retry:
150 if (!opt_password && need_password && !opt_machine_pass) {
151 char *prompt;
152 asprintf(&prompt,"%s's password: ", opt_user_name);
153 opt_password = getpass(prompt);
154 free(prompt);
157 if (opt_password) {
158 use_in_memory_ccache();
159 ads->auth.password = smb_xstrdup(opt_password);
162 ads->auth.user_name = smb_xstrdup(opt_user_name);
165 * If the username is of the form "name@realm",
166 * extract the realm and convert to upper case.
167 * This is only used to establish the connection.
169 if ((cp = strchr(ads->auth.user_name, '@'))!=0) {
170 *cp++ = '\0';
171 ads->auth.realm = smb_xstrdup(cp);
172 strupper_m(ads->auth.realm);
175 status = ads_connect(ads);
177 if (!ADS_ERR_OK(status)) {
178 if (!need_password && !second_time) {
179 need_password = True;
180 second_time = True;
181 goto retry;
182 } else {
183 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
184 return NULL;
187 return ads;
192 Check to see if connection can be made via ads.
193 ads_startup() stores the password in opt_password if it needs to so
194 that rpc or rap can use it without re-prompting.
196 int net_ads_check(void)
198 ADS_STRUCT *ads;
200 ads = ads_startup();
201 if (!ads)
202 return -1;
203 ads_destroy(&ads);
204 return 0;
208 determine the netbios workgroup name for a domain
210 static int net_ads_workgroup(int argc, const char **argv)
212 ADS_STRUCT *ads;
213 TALLOC_CTX *ctx;
214 const char *workgroup;
216 if (!(ads = ads_startup())) return -1;
218 if (!(ctx = talloc_init("net_ads_workgroup"))) {
219 ads_destroy(&ads);
220 return -1;
223 if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
224 d_printf("Failed to find workgroup for realm '%s'\n",
225 ads->config.realm);
226 talloc_destroy(ctx);
227 ads_destroy(&ads);
228 return -1;
231 d_printf("Workgroup: %s\n", workgroup);
233 talloc_destroy(ctx);
234 ads_destroy(&ads);
235 return 0;
240 static BOOL usergrp_display(char *field, void **values, void *data_area)
242 char **disp_fields = (char **) data_area;
244 if (!field) { /* must be end of record */
245 if (!strchr_m(disp_fields[0], '$')) {
246 if (disp_fields[1])
247 d_printf("%-21.21s %s\n",
248 disp_fields[0], disp_fields[1]);
249 else
250 d_printf("%s\n", disp_fields[0]);
252 SAFE_FREE(disp_fields[0]);
253 SAFE_FREE(disp_fields[1]);
254 return True;
256 if (!values) /* must be new field, indicate string field */
257 return True;
258 if (StrCaseCmp(field, "sAMAccountName") == 0) {
259 disp_fields[0] = strdup((char *) values[0]);
261 if (StrCaseCmp(field, "description") == 0)
262 disp_fields[1] = strdup((char *) values[0]);
263 return True;
266 static int net_ads_user_usage(int argc, const char **argv)
268 return net_help_user(argc, argv);
271 static int ads_user_add(int argc, const char **argv)
273 ADS_STRUCT *ads;
274 ADS_STATUS status;
275 char *upn, *userdn;
276 void *res=NULL;
277 int rc = -1;
279 if (argc < 1) return net_ads_user_usage(argc, argv);
281 if (!(ads = ads_startup())) {
282 return -1;
285 status = ads_find_user_acct(ads, &res, argv[0]);
287 if (!ADS_ERR_OK(status)) {
288 d_printf("ads_user_add: %s\n", ads_errstr(status));
289 goto done;
292 if (ads_count_replies(ads, res)) {
293 d_printf("ads_user_add: User %s already exists\n", argv[0]);
294 goto done;
297 status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
299 if (!ADS_ERR_OK(status)) {
300 d_printf("Could not add user %s: %s\n", argv[0],
301 ads_errstr(status));
302 goto done;
305 /* if no password is to be set, we're done */
306 if (argc == 1) {
307 d_printf("User %s added\n", argv[0]);
308 rc = 0;
309 goto done;
312 /* try setting the password */
313 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
314 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
315 ads->auth.time_offset);
316 safe_free(upn);
317 if (ADS_ERR_OK(status)) {
318 d_printf("User %s added\n", argv[0]);
319 rc = 0;
320 goto done;
323 /* password didn't set, delete account */
324 d_printf("Could not add user %s. Error setting password %s\n",
325 argv[0], ads_errstr(status));
326 ads_msgfree(ads, res);
327 status=ads_find_user_acct(ads, &res, argv[0]);
328 if (ADS_ERR_OK(status)) {
329 userdn = ads_get_dn(ads, res);
330 ads_del_dn(ads, userdn);
331 ads_memfree(ads, userdn);
334 done:
335 if (res)
336 ads_msgfree(ads, res);
337 ads_destroy(&ads);
338 return rc;
341 static int ads_user_info(int argc, const char **argv)
343 ADS_STRUCT *ads;
344 ADS_STATUS rc;
345 void *res;
346 const char *attrs[] = {"memberOf", NULL};
347 char *searchstring=NULL;
348 char **grouplist;
349 char *escaped_user = escape_ldap_string_alloc(argv[0]);
351 if (argc < 1) {
352 return net_ads_user_usage(argc, argv);
355 if (!(ads = ads_startup())) {
356 return -1;
359 if (!escaped_user) {
360 d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
361 ads_destroy(&ads);
362 return -1;
365 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
366 rc = ads_search(ads, &res, searchstring, attrs);
367 safe_free(searchstring);
369 if (!ADS_ERR_OK(rc)) {
370 d_printf("ads_search: %s\n", ads_errstr(rc));
371 ads_destroy(&ads);
372 return -1;
375 grouplist = ldap_get_values(ads->ld, res, "memberOf");
377 if (grouplist) {
378 int i;
379 char **groupname;
380 for (i=0;grouplist[i];i++) {
381 groupname = ldap_explode_dn(grouplist[i], 1);
382 d_printf("%s\n", groupname[0]);
383 ldap_value_free(groupname);
385 ldap_value_free(grouplist);
388 ads_msgfree(ads, res);
389 ads_destroy(&ads);
390 return 0;
393 static int ads_user_delete(int argc, const char **argv)
395 ADS_STRUCT *ads;
396 ADS_STATUS rc;
397 void *res;
398 char *userdn;
400 if (argc < 1) {
401 return net_ads_user_usage(argc, argv);
404 if (!(ads = ads_startup())) {
405 return -1;
408 rc = ads_find_user_acct(ads, &res, argv[0]);
409 if (!ADS_ERR_OK(rc)) {
410 DEBUG(0, ("User %s does not exist\n", argv[0]));
411 ads_destroy(&ads);
412 return -1;
414 userdn = ads_get_dn(ads, res);
415 ads_msgfree(ads, res);
416 rc = ads_del_dn(ads, userdn);
417 ads_memfree(ads, userdn);
418 if (!ADS_ERR_OK(rc)) {
419 d_printf("User %s deleted\n", argv[0]);
420 ads_destroy(&ads);
421 return 0;
423 d_printf("Error deleting user %s: %s\n", argv[0],
424 ads_errstr(rc));
425 ads_destroy(&ads);
426 return -1;
429 int net_ads_user(int argc, const char **argv)
431 struct functable func[] = {
432 {"ADD", ads_user_add},
433 {"INFO", ads_user_info},
434 {"DELETE", ads_user_delete},
435 {NULL, NULL}
437 ADS_STRUCT *ads;
438 ADS_STATUS rc;
439 const char *shortattrs[] = {"sAMAccountName", NULL};
440 const char *longattrs[] = {"sAMAccountName", "description", NULL};
441 char *disp_fields[2] = {NULL, NULL};
443 if (argc == 0) {
444 if (!(ads = ads_startup())) {
445 return -1;
448 if (opt_long_list_entries)
449 d_printf("\nUser name Comment"\
450 "\n-----------------------------\n");
452 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
453 LDAP_SCOPE_SUBTREE,
454 "(objectclass=user)",
455 opt_long_list_entries ? longattrs :
456 shortattrs, usergrp_display,
457 disp_fields);
458 ads_destroy(&ads);
459 return 0;
462 return net_run_function(argc, argv, func, net_ads_user_usage);
465 static int net_ads_group_usage(int argc, const char **argv)
467 return net_help_group(argc, argv);
470 static int ads_group_add(int argc, const char **argv)
472 ADS_STRUCT *ads;
473 ADS_STATUS status;
474 void *res=NULL;
475 int rc = -1;
477 if (argc < 1) {
478 return net_ads_group_usage(argc, argv);
481 if (!(ads = ads_startup())) {
482 return -1;
485 status = ads_find_user_acct(ads, &res, argv[0]);
487 if (!ADS_ERR_OK(status)) {
488 d_printf("ads_group_add: %s\n", ads_errstr(status));
489 goto done;
492 if (ads_count_replies(ads, res)) {
493 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
494 ads_msgfree(ads, res);
495 goto done;
498 status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
500 if (ADS_ERR_OK(status)) {
501 d_printf("Group %s added\n", argv[0]);
502 rc = 0;
503 } else {
504 d_printf("Could not add group %s: %s\n", argv[0],
505 ads_errstr(status));
508 done:
509 if (res)
510 ads_msgfree(ads, res);
511 ads_destroy(&ads);
512 return rc;
515 static int ads_group_delete(int argc, const char **argv)
517 ADS_STRUCT *ads;
518 ADS_STATUS rc;
519 void *res;
520 char *groupdn;
522 if (argc < 1) {
523 return net_ads_group_usage(argc, argv);
526 if (!(ads = ads_startup())) {
527 return -1;
530 rc = ads_find_user_acct(ads, &res, argv[0]);
531 if (!ADS_ERR_OK(rc)) {
532 DEBUG(0, ("Group %s does not exist\n", argv[0]));
533 ads_destroy(&ads);
534 return -1;
536 groupdn = ads_get_dn(ads, res);
537 ads_msgfree(ads, res);
538 rc = ads_del_dn(ads, groupdn);
539 ads_memfree(ads, groupdn);
540 if (!ADS_ERR_OK(rc)) {
541 d_printf("Group %s deleted\n", argv[0]);
542 ads_destroy(&ads);
543 return 0;
545 d_printf("Error deleting group %s: %s\n", argv[0],
546 ads_errstr(rc));
547 ads_destroy(&ads);
548 return -1;
551 int net_ads_group(int argc, const char **argv)
553 struct functable func[] = {
554 {"ADD", ads_group_add},
555 {"DELETE", ads_group_delete},
556 {NULL, NULL}
558 ADS_STRUCT *ads;
559 ADS_STATUS rc;
560 const char *shortattrs[] = {"sAMAccountName", NULL};
561 const char *longattrs[] = {"sAMAccountName", "description", NULL};
562 char *disp_fields[2] = {NULL, NULL};
564 if (argc == 0) {
565 if (!(ads = ads_startup())) {
566 return -1;
569 if (opt_long_list_entries)
570 d_printf("\nGroup name Comment"\
571 "\n-----------------------------\n");
572 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
573 LDAP_SCOPE_SUBTREE,
574 "(objectclass=group)",
575 opt_long_list_entries ? longattrs :
576 shortattrs, usergrp_display,
577 disp_fields);
579 ads_destroy(&ads);
580 return 0;
582 return net_run_function(argc, argv, func, net_ads_group_usage);
585 static int net_ads_status(int argc, const char **argv)
587 ADS_STRUCT *ads;
588 ADS_STATUS rc;
589 void *res;
591 if (!(ads = ads_startup())) {
592 return -1;
595 rc = ads_find_machine_acct(ads, &res, global_myname());
596 if (!ADS_ERR_OK(rc)) {
597 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
598 ads_destroy(&ads);
599 return -1;
602 if (ads_count_replies(ads, res) == 0) {
603 d_printf("No machine account for '%s' found\n", global_myname());
604 ads_destroy(&ads);
605 return -1;
608 ads_dump(ads, res);
609 ads_destroy(&ads);
610 return 0;
613 static int net_ads_leave(int argc, const char **argv)
615 ADS_STRUCT *ads = NULL;
616 ADS_STATUS rc;
618 if (!secrets_init()) {
619 DEBUG(1,("Failed to initialise secrets database\n"));
620 return -1;
623 if (!opt_password) {
624 net_use_machine_password();
627 if (!(ads = ads_startup())) {
628 return -1;
631 rc = ads_leave_realm(ads, global_myname());
632 if (!ADS_ERR_OK(rc)) {
633 d_printf("Failed to delete host '%s' from the '%s' realm.\n",
634 global_myname(), ads->config.realm);
635 ads_destroy(&ads);
636 return -1;
639 d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
640 ads_destroy(&ads);
641 return 0;
644 static int net_ads_join_ok(void)
646 ADS_STRUCT *ads = NULL;
648 if (!secrets_init()) {
649 DEBUG(1,("Failed to initialise secrets database\n"));
650 return -1;
653 net_use_machine_password();
655 if (!(ads = ads_startup())) {
656 return -1;
659 ads_destroy(&ads);
660 return 0;
664 check that an existing join is OK
666 int net_ads_testjoin(int argc, const char **argv)
668 use_in_memory_ccache();
670 /* Display success or failure */
671 if (net_ads_join_ok() != 0) {
672 fprintf(stderr,"Join to domain is not valid\n");
673 return -1;
676 printf("Join is OK\n");
677 return 0;
681 join a domain using ADS
683 int net_ads_join(int argc, const char **argv)
685 ADS_STRUCT *ads;
686 ADS_STATUS rc;
687 char *password;
688 char *machine_account = NULL;
689 char *tmp_password;
690 const char *org_unit = "Computers";
691 char *dn;
692 void *res;
693 DOM_SID dom_sid;
694 char *ou_str;
695 uint32 sec_channel_type = SEC_CHAN_WKSTA;
696 uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT;
697 const char *short_domain_name = NULL;
698 TALLOC_CTX *ctx = NULL;
700 if (argc > 0) {
701 org_unit = argv[0];
704 if (!secrets_init()) {
705 DEBUG(1,("Failed to initialise secrets database\n"));
706 return -1;
709 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
710 password = strdup(tmp_password);
712 if (!(ads = ads_startup())) {
713 return -1;
716 if (!*lp_realm()) {
717 d_printf("realm must be set in in smb.conf for ADS join to succeed.\n");
718 ads_destroy(&ads);
719 return -1;
722 if (strcmp(ads->config.realm, lp_realm()) != 0) {
723 d_printf("realm of remote server (%s) and realm in smb.conf (%s) DO NOT match. Aborting join\n", ads->config.realm, lp_realm());
724 ads_destroy(&ads);
725 return -1;
728 ou_str = ads_ou_string(org_unit);
729 asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
730 free(ou_str);
732 rc = ads_search_dn(ads, &res, dn, NULL);
733 ads_msgfree(ads, res);
735 if (rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
736 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
737 org_unit, dn);
738 ads_destroy(&ads);
739 return -1;
741 free(dn);
743 if (!ADS_ERR_OK(rc)) {
744 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
745 ads_destroy(&ads);
746 return -1;
749 rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
750 if (!ADS_ERR_OK(rc)) {
751 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
752 ads_destroy(&ads);
753 return -1;
756 rc = ads_domain_sid(ads, &dom_sid);
757 if (!ADS_ERR_OK(rc)) {
758 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
759 ads_destroy(&ads);
760 return -1;
763 if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
764 d_printf("asprintf failed\n");
765 ads_destroy(&ads);
766 return -1;
769 rc = ads_set_machine_password(ads, machine_account, password);
770 if (!ADS_ERR_OK(rc)) {
771 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
772 ads_destroy(&ads);
773 return -1;
776 /* make sure we get the right workgroup */
778 if ( !(ctx = talloc_init("net ads join")) ) {
779 d_printf("talloc_init() failed!\n");
780 ads_destroy(&ads);
781 return -1;
784 rc = ads_workgroup_name(ads, ctx, &short_domain_name);
785 if ( ADS_ERR_OK(rc) ) {
786 if ( !strequal(lp_workgroup(), short_domain_name) ) {
787 d_printf("The workgroup in smb.conf does not match the short\n");
788 d_printf("domain name obtained from the server.\n");
789 d_printf("Using the name [%s] from the server.\n", short_domain_name);
790 d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
792 } else {
793 short_domain_name = lp_workgroup();
796 d_printf("Using short domain name -- %s\n", short_domain_name);
798 /* HACK ALRET! Store the sid and password under bother the lp_workgroup()
799 value from smb.conf and the string returned from the server. The former is
800 neede to bootstrap winbindd's first connection to the DC to get the real
801 short domain name --jerry */
803 if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
804 DEBUG(1,("Failed to save domain sid\n"));
805 ads_destroy(&ads);
806 return -1;
809 if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
810 DEBUG(1,("Failed to save machine password\n"));
811 ads_destroy(&ads);
812 return -1;
815 if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) {
816 DEBUG(1,("Failed to save domain sid\n"));
817 ads_destroy(&ads);
818 return -1;
821 if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) {
822 DEBUG(1,("Failed to save machine password\n"));
823 ads_destroy(&ads);
824 return -1;
827 /* Now build the keytab, using the same ADS connection */
828 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
829 DEBUG(1,("Error creating host keytab!\n"));
832 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
834 SAFE_FREE(password);
835 SAFE_FREE(machine_account);
836 if ( ctx ) {
837 talloc_destroy(ctx);
839 ads_destroy(&ads);
840 return 0;
843 int net_ads_printer_usage(int argc, const char **argv)
845 d_printf(
846 "\nnet ads printer search <printer>"
847 "\n\tsearch for a printer in the directory"
848 "\nnet ads printer info <printer> <server>"
849 "\n\tlookup info in directory for printer on server"
850 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
851 "\nnet ads printer publish <printername>"
852 "\n\tpublish printer in directory"
853 "\n\t(note: printer name is required)\n"
854 "\nnet ads printer remove <printername>"
855 "\n\tremove printer from directory"
856 "\n\t(note: printer name is required)\n");
857 return -1;
860 static int net_ads_printer_search(int argc, const char **argv)
862 ADS_STRUCT *ads;
863 ADS_STATUS rc;
864 void *res = NULL;
866 if (!(ads = ads_startup())) {
867 return -1;
870 rc = ads_find_printers(ads, &res);
872 if (!ADS_ERR_OK(rc)) {
873 d_printf("ads_find_printer: %s\n", ads_errstr(rc));
874 ads_msgfree(ads, res);
875 ads_destroy(&ads);
876 return -1;
879 if (ads_count_replies(ads, res) == 0) {
880 d_printf("No results found\n");
881 ads_msgfree(ads, res);
882 ads_destroy(&ads);
883 return -1;
886 ads_dump(ads, res);
887 ads_msgfree(ads, res);
888 ads_destroy(&ads);
889 return 0;
892 static int net_ads_printer_info(int argc, const char **argv)
894 ADS_STRUCT *ads;
895 ADS_STATUS rc;
896 const char *servername, *printername;
897 void *res = NULL;
899 if (!(ads = ads_startup())) {
900 return -1;
903 if (argc > 0) {
904 printername = argv[0];
905 } else {
906 printername = "*";
909 if (argc > 1) {
910 servername = argv[1];
911 } else {
912 servername = global_myname();
915 rc = ads_find_printer_on_server(ads, &res, printername, servername);
917 if (!ADS_ERR_OK(rc)) {
918 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
919 ads_msgfree(ads, res);
920 ads_destroy(&ads);
921 return -1;
924 if (ads_count_replies(ads, res) == 0) {
925 d_printf("Printer '%s' not found\n", printername);
926 ads_msgfree(ads, res);
927 ads_destroy(&ads);
928 return -1;
931 ads_dump(ads, res);
932 ads_msgfree(ads, res);
933 ads_destroy(&ads);
935 return 0;
938 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
940 return;
943 static int net_ads_printer_publish(int argc, const char **argv)
945 ADS_STRUCT *ads;
946 ADS_STATUS rc;
947 const char *servername, *printername;
948 struct cli_state *cli;
949 struct in_addr server_ip;
950 NTSTATUS nt_status;
951 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
952 ADS_MODLIST mods = ads_init_mods(mem_ctx);
953 char *prt_dn, *srv_dn, **srv_cn;
954 void *res = NULL;
956 if (!(ads = ads_startup())) {
957 return -1;
960 if (argc < 1) {
961 return net_ads_printer_usage(argc, argv);
964 printername = argv[0];
966 if (argc == 2) {
967 servername = argv[1];
968 } else {
969 servername = global_myname();
972 /* Get printer data from SPOOLSS */
974 resolve_name(servername, &server_ip, 0x20);
976 nt_status = cli_full_connection(&cli, global_myname(), servername,
977 &server_ip, 0,
978 "IPC$", "IPC",
979 opt_user_name, opt_workgroup,
980 opt_password ? opt_password : "",
981 CLI_FULL_CONNECTION_USE_KERBEROS,
982 Undefined, NULL);
984 if (NT_STATUS_IS_ERR(nt_status)) {
985 d_printf("Unable to open a connnection to %s to obtain data "
986 "for %s\n", servername, printername);
987 ads_destroy(&ads);
988 return -1;
991 /* Publish on AD server */
993 ads_find_machine_acct(ads, &res, servername);
995 if (ads_count_replies(ads, res) == 0) {
996 d_printf("Could not find machine account for server %s\n",
997 servername);
998 ads_destroy(&ads);
999 return -1;
1002 srv_dn = ldap_get_dn(ads->ld, res);
1003 srv_cn = ldap_explode_dn(srv_dn, 1);
1005 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
1007 cli_nt_session_open(cli, PI_SPOOLSS);
1008 get_remote_printer_publishing_data(cli, mem_ctx, &mods, printername);
1010 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1011 if (!ADS_ERR_OK(rc)) {
1012 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
1013 ads_destroy(&ads);
1014 return -1;
1017 d_printf("published printer\n");
1018 ads_destroy(&ads);
1020 return 0;
1023 static int net_ads_printer_remove(int argc, const char **argv)
1025 ADS_STRUCT *ads;
1026 ADS_STATUS rc;
1027 const char *servername;
1028 char *prt_dn;
1029 void *res = NULL;
1031 if (!(ads = ads_startup())) {
1032 return -1;
1035 if (argc < 1) {
1036 return net_ads_printer_usage(argc, argv);
1039 if (argc > 1) {
1040 servername = argv[1];
1041 } else {
1042 servername = global_myname();
1045 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1047 if (!ADS_ERR_OK(rc)) {
1048 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
1049 ads_msgfree(ads, res);
1050 ads_destroy(&ads);
1051 return -1;
1054 if (ads_count_replies(ads, res) == 0) {
1055 d_printf("Printer '%s' not found\n", argv[1]);
1056 ads_msgfree(ads, res);
1057 ads_destroy(&ads);
1058 return -1;
1061 prt_dn = ads_get_dn(ads, res);
1062 ads_msgfree(ads, res);
1063 rc = ads_del_dn(ads, prt_dn);
1064 ads_memfree(ads, prt_dn);
1066 if (!ADS_ERR_OK(rc)) {
1067 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
1068 ads_destroy(&ads);
1069 return -1;
1072 ads_destroy(&ads);
1073 return 0;
1076 static int net_ads_printer(int argc, const char **argv)
1078 struct functable func[] = {
1079 {"SEARCH", net_ads_printer_search},
1080 {"INFO", net_ads_printer_info},
1081 {"PUBLISH", net_ads_printer_publish},
1082 {"REMOVE", net_ads_printer_remove},
1083 {NULL, NULL}
1086 return net_run_function(argc, argv, func, net_ads_printer_usage);
1090 static int net_ads_password(int argc, const char **argv)
1092 ADS_STRUCT *ads;
1093 const char *auth_principal = opt_user_name;
1094 const char *auth_password = opt_password;
1095 char *realm = NULL;
1096 char *new_password = NULL;
1097 char *c, *prompt;
1098 const char *user;
1099 ADS_STATUS ret;
1101 if (opt_user_name == NULL || opt_password == NULL) {
1102 d_printf("You must supply an administrator username/password\n");
1103 return -1;
1106 if (argc < 1) {
1107 d_printf("ERROR: You must say which username to change password for\n");
1108 return -1;
1111 user = argv[0];
1112 if (!strchr_m(user, '@')) {
1113 asprintf(&c, "%s@%s", argv[0], lp_realm());
1114 user = c;
1117 use_in_memory_ccache();
1118 c = strchr(auth_principal, '@');
1119 if (c) {
1120 realm = ++c;
1121 } else {
1122 realm = lp_realm();
1125 /* use the realm so we can eventually change passwords for users
1126 in realms other than default */
1127 if (!(ads = ads_init(realm, NULL, NULL))) {
1128 return -1;
1131 /* we don't actually need a full connect, but it's the easy way to
1132 fill in the KDC's addresss */
1133 ads_connect(ads);
1135 if (!ads || !ads->config.realm) {
1136 d_printf("Didn't find the kerberos server!\n");
1137 return -1;
1140 if (argv[1]) {
1141 new_password = (char *)argv[1];
1142 } else {
1143 asprintf(&prompt, "Enter new password for %s:", user);
1144 new_password = getpass(prompt);
1145 free(prompt);
1148 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1149 auth_password, user, new_password, ads->auth.time_offset);
1150 if (!ADS_ERR_OK(ret)) {
1151 d_printf("Password change failed :-( ...\n");
1152 ads_destroy(&ads);
1153 return -1;
1156 d_printf("Password change for %s completed.\n", user);
1157 ads_destroy(&ads);
1159 return 0;
1162 int net_ads_changetrustpw(int argc, const char **argv)
1164 ADS_STRUCT *ads;
1165 char *host_principal;
1166 fstring my_name;
1167 ADS_STATUS ret;
1169 if (!secrets_init()) {
1170 DEBUG(1,("Failed to initialise secrets database\n"));
1171 return -1;
1174 net_use_machine_password();
1176 use_in_memory_ccache();
1178 if (!(ads = ads_startup())) {
1179 return -1;
1182 fstrcpy(my_name, global_myname());
1183 strlower_m(my_name);
1184 asprintf(&host_principal, "%s@%s", my_name, ads->config.realm);
1185 d_printf("Changing password for principal: HOST/%s\n", host_principal);
1187 ret = ads_change_trust_account_password(ads, host_principal);
1189 if (!ADS_ERR_OK(ret)) {
1190 d_printf("Password change failed :-( ...\n");
1191 ads_destroy(&ads);
1192 SAFE_FREE(host_principal);
1193 return -1;
1196 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
1198 if (lp_use_kerberos_keytab()) {
1199 d_printf("Attempting to update system keytab with new password.\n");
1200 if (ads_keytab_create_default(ads)) {
1201 d_printf("Failed to update system keytab.\n");
1205 ads_destroy(&ads);
1206 SAFE_FREE(host_principal);
1208 return 0;
1212 help for net ads search
1214 static int net_ads_search_usage(int argc, const char **argv)
1216 d_printf(
1217 "\nnet ads search <expression> <attributes...>\n"\
1218 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1219 "The expression is a standard LDAP search expression, and the\n"\
1220 "attributes are a list of LDAP fields to show in the results\n\n"\
1221 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1223 net_common_flags_usage(argc, argv);
1224 return -1;
1229 general ADS search function. Useful in diagnosing problems in ADS
1231 static int net_ads_search(int argc, const char **argv)
1233 ADS_STRUCT *ads;
1234 ADS_STATUS rc;
1235 const char *ldap_exp;
1236 const char **attrs;
1237 void *res = NULL;
1239 if (argc < 1) {
1240 return net_ads_search_usage(argc, argv);
1243 if (!(ads = ads_startup())) {
1244 return -1;
1247 ldap_exp = argv[0];
1248 attrs = (argv + 1);
1250 rc = ads_do_search_all(ads, ads->config.bind_path,
1251 LDAP_SCOPE_SUBTREE,
1252 ldap_exp, attrs, &res);
1253 if (!ADS_ERR_OK(rc)) {
1254 d_printf("search failed: %s\n", ads_errstr(rc));
1255 ads_destroy(&ads);
1256 return -1;
1259 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1261 /* dump the results */
1262 ads_dump(ads, res);
1264 ads_msgfree(ads, res);
1265 ads_destroy(&ads);
1267 return 0;
1272 help for net ads search
1274 static int net_ads_dn_usage(int argc, const char **argv)
1276 d_printf(
1277 "\nnet ads dn <dn> <attributes...>\n"\
1278 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1279 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1280 "to show in the results\n\n"\
1281 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1283 net_common_flags_usage(argc, argv);
1284 return -1;
1289 general ADS search function. Useful in diagnosing problems in ADS
1291 static int net_ads_dn(int argc, const char **argv)
1293 ADS_STRUCT *ads;
1294 ADS_STATUS rc;
1295 const char *dn;
1296 const char **attrs;
1297 void *res = NULL;
1299 if (argc < 1) {
1300 return net_ads_dn_usage(argc, argv);
1303 if (!(ads = ads_startup())) {
1304 return -1;
1307 dn = argv[0];
1308 attrs = (argv + 1);
1310 rc = ads_do_search_all(ads, dn,
1311 LDAP_SCOPE_BASE,
1312 "(objectclass=*)", attrs, &res);
1313 if (!ADS_ERR_OK(rc)) {
1314 d_printf("search failed: %s\n", ads_errstr(rc));
1315 ads_destroy(&ads);
1316 return -1;
1319 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1321 /* dump the results */
1322 ads_dump(ads, res);
1324 ads_msgfree(ads, res);
1325 ads_destroy(&ads);
1327 return 0;
1330 static int net_ads_keytab_usage(int argc, const char **argv)
1332 d_printf(
1333 "net ads keytab <COMMAND>\n"\
1334 "<COMMAND> can be either:\n"\
1335 " CREATE Creates a fresh keytab\n"\
1336 " ADD Adds new service principal\n"\
1337 " FLUSH Flushes out all keytab entries\n"\
1338 " HELP Prints this help message\n"\
1339 "The ADD command will take arguments, the other commands\n"\
1340 "will not take any arguments. The arguments given to ADD\n"\
1341 "should be a list of principals to add. For example, \n"\
1342 " net ads keytab add srv1 srv2\n"\
1343 "will add principals for the services srv1 and srv2 to the\n"\
1344 "system's keytab.\n"\
1345 "\n"
1347 return -1;
1350 static int net_ads_keytab_flush(int argc, const char **argv)
1352 int ret;
1353 ADS_STRUCT *ads;
1355 if (!(ads = ads_startup())) {
1356 return -1;
1358 ret = ads_keytab_flush(ads);
1359 ads_destroy(&ads);
1360 return ret;
1363 static int net_ads_keytab_add(int argc, const char **argv)
1365 int i;
1366 int ret = 0;
1367 ADS_STRUCT *ads;
1369 d_printf("Processing principals to add...\n");
1370 if (!(ads = ads_startup())) {
1371 return -1;
1373 for (i = 0; i < argc; i++) {
1374 ret |= ads_keytab_add_entry(ads, argv[i]);
1376 ads_destroy(&ads);
1377 return ret;
1380 static int net_ads_keytab_create(int argc, const char **argv)
1382 ADS_STRUCT *ads;
1383 int ret;
1385 if (!(ads = ads_startup())) {
1386 return -1;
1388 ret = ads_keytab_create_default(ads);
1389 ads_destroy(&ads);
1390 return ret;
1393 int net_ads_keytab(int argc, const char **argv)
1395 struct functable func[] = {
1396 {"CREATE", net_ads_keytab_create},
1397 {"ADD", net_ads_keytab_add},
1398 {"FLUSH", net_ads_keytab_flush},
1399 {"HELP", net_ads_keytab_usage},
1400 {NULL, NULL}
1403 if (!lp_use_kerberos_keytab()) {
1404 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
1405 use keytab functions.\n");
1408 return net_run_function(argc, argv, func, net_ads_keytab_usage);
1411 int net_ads_help(int argc, const char **argv)
1413 struct functable func[] = {
1414 {"USER", net_ads_user_usage},
1415 {"GROUP", net_ads_group_usage},
1416 {"PRINTER", net_ads_printer_usage},
1417 {"SEARCH", net_ads_search_usage},
1418 #if 0
1419 {"INFO", net_ads_info},
1420 {"JOIN", net_ads_join},
1421 {"LEAVE", net_ads_leave},
1422 {"STATUS", net_ads_status},
1423 {"PASSWORD", net_ads_password},
1424 {"CHANGETRUSTPW", net_ads_changetrustpw},
1425 #endif
1426 {NULL, NULL}
1429 return net_run_function(argc, argv, func, net_ads_usage);
1432 int net_ads(int argc, const char **argv)
1434 struct functable func[] = {
1435 {"INFO", net_ads_info},
1436 {"JOIN", net_ads_join},
1437 {"TESTJOIN", net_ads_testjoin},
1438 {"LEAVE", net_ads_leave},
1439 {"STATUS", net_ads_status},
1440 {"USER", net_ads_user},
1441 {"GROUP", net_ads_group},
1442 {"PASSWORD", net_ads_password},
1443 {"CHANGETRUSTPW", net_ads_changetrustpw},
1444 {"PRINTER", net_ads_printer},
1445 {"SEARCH", net_ads_search},
1446 {"DN", net_ads_dn},
1447 {"WORKGROUP", net_ads_workgroup},
1448 {"LOOKUP", net_ads_lookup},
1449 {"KEYTAB", net_ads_keytab},
1450 {"HELP", net_ads_help},
1451 {NULL, NULL}
1454 return net_run_function(argc, argv, func, net_ads_usage);
1457 #else
1459 static int net_ads_noads(void)
1461 d_printf("ADS support not compiled in\n");
1462 return -1;
1465 int net_ads_keytab(int argc, const char **argv)
1467 return net_ads_noads();
1470 int net_ads_usage(int argc, const char **argv)
1472 return net_ads_noads();
1475 int net_ads_help(int argc, const char **argv)
1477 return net_ads_noads();
1480 int net_ads_changetrustpw(int argc, const char **argv)
1482 return net_ads_noads();
1485 int net_ads_join(int argc, const char **argv)
1487 return net_ads_noads();
1490 int net_ads_user(int argc, const char **argv)
1492 return net_ads_noads();
1495 int net_ads_group(int argc, const char **argv)
1497 return net_ads_noads();
1500 /* this one shouldn't display a message */
1501 int net_ads_check(void)
1503 return -1;
1506 int net_ads(int argc, const char **argv)
1508 return net_ads_usage(argc, argv);
1511 #endif