Clean up a comment noticed by Jonathan Shao@Panasas.com and remove an
[Samba/gebeck_regimport.git] / source3 / utils / net_ads.c
blob9404ae4b247b5e56bf44e26cf4c8bbf433273332
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> -Uadmin_username@realm%%admin_pass"\
48 "\n\tchange a user's password using an admin account"\
49 "\n\t(note: use realm in UPPERCASE)\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"
59 return -1;
64 this implements the CLDAP based netlogon lookup requests
65 for finding the domain controller of a ADS domain
67 static int net_ads_lookup(int argc, const char **argv)
69 ADS_STRUCT *ads;
71 ads = ads_init(NULL, opt_target_workgroup, opt_host);
72 if (ads) {
73 ads->auth.flags |= ADS_AUTH_NO_BIND;
76 ads_connect(ads);
78 if (!ads || !ads->config.realm) {
79 d_printf("Didn't find the cldap server!\n");
80 return -1;
83 return ads_cldap_netlogon(ads);
88 static int net_ads_info(int argc, const char **argv)
90 ADS_STRUCT *ads;
92 ads = ads_init(NULL, opt_target_workgroup, opt_host);
94 if (ads) {
95 ads->auth.flags |= ADS_AUTH_NO_BIND;
98 ads_connect(ads);
100 if (!ads || !ads->config.realm) {
101 d_printf("Didn't find the ldap server!\n");
102 return -1;
105 d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
106 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
107 d_printf("Realm: %s\n", ads->config.realm);
108 d_printf("Bind Path: %s\n", ads->config.bind_path);
109 d_printf("LDAP port: %d\n", ads->ldap_port);
110 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
112 d_printf("KDC server: %s\n", ads->auth.kdc_server );
113 d_printf("Server time offset: %d\n", ads->auth.time_offset );
115 return 0;
118 static void use_in_memory_ccache(void) {
119 /* Use in-memory credentials cache so we do not interfere with
120 * existing credentials */
121 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
124 static ADS_STRUCT *ads_startup(void)
126 ADS_STRUCT *ads;
127 ADS_STATUS status;
128 BOOL need_password = False;
129 BOOL second_time = False;
130 char *cp;
132 /* lp_realm() should be handled by a command line param,
133 However, the join requires that realm be set in smb.conf
134 and compares our realm with the remote server's so this is
135 ok until someone needs more flexibility */
137 ads = ads_init(lp_realm(), opt_target_workgroup, opt_host);
139 if (!opt_user_name) {
140 opt_user_name = "administrator";
143 if (opt_user_specified) {
144 need_password = True;
147 retry:
148 if (!opt_password && need_password && !opt_machine_pass) {
149 char *prompt;
150 asprintf(&prompt,"%s password: ", opt_user_name);
151 opt_password = getpass(prompt);
152 free(prompt);
155 if (opt_password) {
156 use_in_memory_ccache();
157 ads->auth.password = smb_xstrdup(opt_password);
160 ads->auth.user_name = smb_xstrdup(opt_user_name);
163 * If the username is of the form "name@realm",
164 * extract the realm and convert to upper case.
165 * This is only used to establish the connection.
167 if ((cp = strchr(ads->auth.user_name, '@'))!=0) {
168 *cp++ = '\0';
169 ads->auth.realm = smb_xstrdup(cp);
170 strupper_m(ads->auth.realm);
173 status = ads_connect(ads);
175 if (!ADS_ERR_OK(status)) {
176 if (!need_password && !second_time) {
177 need_password = True;
178 second_time = True;
179 goto retry;
180 } else {
181 DEBUG(1,("ads_connect: %s\n", ads_errstr(status)));
182 return NULL;
185 return ads;
190 Check to see if connection can be made via ads.
191 ads_startup() stores the password in opt_password if it needs to so
192 that rpc or rap can use it without re-prompting.
194 int net_ads_check(void)
196 ADS_STRUCT *ads;
198 ads = ads_startup();
199 if (!ads)
200 return -1;
201 ads_destroy(&ads);
202 return 0;
206 determine the netbios workgroup name for a domain
208 static int net_ads_workgroup(int argc, const char **argv)
210 ADS_STRUCT *ads;
211 TALLOC_CTX *ctx;
212 const char *workgroup;
214 if (!(ads = ads_startup())) return -1;
216 if (!(ctx = talloc_init("net_ads_workgroup"))) {
217 return -1;
220 if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
221 d_printf("Failed to find workgroup for realm '%s'\n",
222 ads->config.realm);
223 talloc_destroy(ctx);
224 return -1;
227 d_printf("Workgroup: %s\n", workgroup);
229 talloc_destroy(ctx);
231 return 0;
236 static BOOL usergrp_display(char *field, void **values, void *data_area)
238 char **disp_fields = (char **) data_area;
240 if (!field) { /* must be end of record */
241 if (!strchr_m(disp_fields[0], '$')) {
242 if (disp_fields[1])
243 d_printf("%-21.21s %s\n",
244 disp_fields[0], disp_fields[1]);
245 else
246 d_printf("%s\n", disp_fields[0]);
248 SAFE_FREE(disp_fields[0]);
249 SAFE_FREE(disp_fields[1]);
250 return True;
252 if (!values) /* must be new field, indicate string field */
253 return True;
254 if (StrCaseCmp(field, "sAMAccountName") == 0) {
255 disp_fields[0] = strdup((char *) values[0]);
257 if (StrCaseCmp(field, "description") == 0)
258 disp_fields[1] = strdup((char *) values[0]);
259 return True;
262 static int net_ads_user_usage(int argc, const char **argv)
264 return net_help_user(argc, argv);
267 static int ads_user_add(int argc, const char **argv)
269 ADS_STRUCT *ads;
270 ADS_STATUS status;
271 char *upn, *userdn;
272 void *res=NULL;
273 int rc = -1;
275 if (argc < 1) return net_ads_user_usage(argc, argv);
277 if (!(ads = ads_startup())) return -1;
279 status = ads_find_user_acct(ads, &res, argv[0]);
281 if (!ADS_ERR_OK(status)) {
282 d_printf("ads_user_add: %s\n", ads_errstr(status));
283 goto done;
286 if (ads_count_replies(ads, res)) {
287 d_printf("ads_user_add: User %s already exists\n", argv[0]);
288 goto done;
291 status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
293 if (!ADS_ERR_OK(status)) {
294 d_printf("Could not add user %s: %s\n", argv[0],
295 ads_errstr(status));
296 goto done;
299 /* if no password is to be set, we're done */
300 if (argc == 1) {
301 d_printf("User %s added\n", argv[0]);
302 rc = 0;
303 goto done;
306 /* try setting the password */
307 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
308 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
309 ads->auth.time_offset);
310 safe_free(upn);
311 if (ADS_ERR_OK(status)) {
312 d_printf("User %s added\n", argv[0]);
313 rc = 0;
314 goto done;
317 /* password didn't set, delete account */
318 d_printf("Could not add user %s. Error setting password %s\n",
319 argv[0], ads_errstr(status));
320 ads_msgfree(ads, res);
321 status=ads_find_user_acct(ads, &res, argv[0]);
322 if (ADS_ERR_OK(status)) {
323 userdn = ads_get_dn(ads, res);
324 ads_del_dn(ads, userdn);
325 ads_memfree(ads, userdn);
328 done:
329 if (res)
330 ads_msgfree(ads, res);
331 ads_destroy(&ads);
332 return rc;
335 static int ads_user_info(int argc, const char **argv)
337 ADS_STRUCT *ads;
338 ADS_STATUS rc;
339 void *res;
340 const char *attrs[] = {"memberOf", NULL};
341 char *searchstring=NULL;
342 char **grouplist;
343 char *escaped_user = escape_ldap_string_alloc(argv[0]);
345 if (argc < 1) return net_ads_user_usage(argc, argv);
347 if (!(ads = ads_startup())) return -1;
349 if (!escaped_user) {
350 d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
351 return -1;
354 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
355 rc = ads_search(ads, &res, searchstring, attrs);
356 safe_free(searchstring);
358 if (!ADS_ERR_OK(rc)) {
359 d_printf("ads_search: %s\n", ads_errstr(rc));
360 return -1;
363 grouplist = ldap_get_values(ads->ld, res, "memberOf");
365 if (grouplist) {
366 int i;
367 char **groupname;
368 for (i=0;grouplist[i];i++) {
369 groupname = ldap_explode_dn(grouplist[i], 1);
370 d_printf("%s\n", groupname[0]);
371 ldap_value_free(groupname);
373 ldap_value_free(grouplist);
376 ads_msgfree(ads, res);
378 ads_destroy(&ads);
379 return 0;
382 static int ads_user_delete(int argc, const char **argv)
384 ADS_STRUCT *ads;
385 ADS_STATUS rc;
386 void *res;
387 char *userdn;
389 if (argc < 1) return net_ads_user_usage(argc, argv);
391 if (!(ads = ads_startup())) return -1;
393 rc = ads_find_user_acct(ads, &res, argv[0]);
394 if (!ADS_ERR_OK(rc)) {
395 DEBUG(0, ("User %s does not exist\n", argv[0]));
396 return -1;
398 userdn = ads_get_dn(ads, res);
399 ads_msgfree(ads, res);
400 rc = ads_del_dn(ads, userdn);
401 ads_memfree(ads, userdn);
402 if (!ADS_ERR_OK(rc)) {
403 d_printf("User %s deleted\n", argv[0]);
404 return 0;
406 d_printf("Error deleting user %s: %s\n", argv[0],
407 ads_errstr(rc));
408 return -1;
411 int net_ads_user(int argc, const char **argv)
413 struct functable func[] = {
414 {"ADD", ads_user_add},
415 {"INFO", ads_user_info},
416 {"DELETE", ads_user_delete},
417 {NULL, NULL}
419 ADS_STRUCT *ads;
420 ADS_STATUS rc;
421 const char *shortattrs[] = {"sAMAccountName", NULL};
422 const char *longattrs[] = {"sAMAccountName", "description", NULL};
423 char *disp_fields[2] = {NULL, NULL};
425 if (argc == 0) {
426 if (!(ads = ads_startup())) return -1;
428 if (opt_long_list_entries)
429 d_printf("\nUser name Comment"\
430 "\n-----------------------------\n");
432 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
433 LDAP_SCOPE_SUBTREE,
434 "(objectclass=user)",
435 opt_long_list_entries ? longattrs :
436 shortattrs, usergrp_display,
437 disp_fields);
438 ads_destroy(&ads);
439 return 0;
442 return net_run_function(argc, argv, func, net_ads_user_usage);
445 static int net_ads_group_usage(int argc, const char **argv)
447 return net_help_group(argc, argv);
450 static int ads_group_add(int argc, const char **argv)
452 ADS_STRUCT *ads;
453 ADS_STATUS status;
454 void *res=NULL;
455 int rc = -1;
457 if (argc < 1) return net_ads_group_usage(argc, argv);
459 if (!(ads = ads_startup())) return -1;
461 status = ads_find_user_acct(ads, &res, argv[0]);
463 if (!ADS_ERR_OK(status)) {
464 d_printf("ads_group_add: %s\n", ads_errstr(status));
465 goto done;
468 if (ads_count_replies(ads, res)) {
469 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
470 ads_msgfree(ads, res);
471 goto done;
474 status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
476 if (ADS_ERR_OK(status)) {
477 d_printf("Group %s added\n", argv[0]);
478 rc = 0;
479 } else {
480 d_printf("Could not add group %s: %s\n", argv[0],
481 ads_errstr(status));
484 done:
485 if (res)
486 ads_msgfree(ads, res);
487 ads_destroy(&ads);
488 return rc;
491 static int ads_group_delete(int argc, const char **argv)
493 ADS_STRUCT *ads;
494 ADS_STATUS rc;
495 void *res;
496 char *groupdn;
498 if (argc < 1) return net_ads_group_usage(argc, argv);
500 if (!(ads = ads_startup())) return -1;
502 rc = ads_find_user_acct(ads, &res, argv[0]);
503 if (!ADS_ERR_OK(rc)) {
504 DEBUG(0, ("Group %s does not exist\n", argv[0]));
505 return -1;
507 groupdn = ads_get_dn(ads, res);
508 ads_msgfree(ads, res);
509 rc = ads_del_dn(ads, groupdn);
510 ads_memfree(ads, groupdn);
511 if (!ADS_ERR_OK(rc)) {
512 d_printf("Group %s deleted\n", argv[0]);
513 return 0;
515 d_printf("Error deleting group %s: %s\n", argv[0],
516 ads_errstr(rc));
517 return -1;
520 int net_ads_group(int argc, const char **argv)
522 struct functable func[] = {
523 {"ADD", ads_group_add},
524 {"DELETE", ads_group_delete},
525 {NULL, NULL}
527 ADS_STRUCT *ads;
528 ADS_STATUS rc;
529 const char *shortattrs[] = {"sAMAccountName", NULL};
530 const char *longattrs[] = {"sAMAccountName", "description", NULL};
531 char *disp_fields[2] = {NULL, NULL};
533 if (argc == 0) {
534 if (!(ads = ads_startup())) return -1;
536 if (opt_long_list_entries)
537 d_printf("\nGroup name Comment"\
538 "\n-----------------------------\n");
539 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
540 LDAP_SCOPE_SUBTREE,
541 "(objectclass=group)",
542 opt_long_list_entries ? longattrs :
543 shortattrs, usergrp_display,
544 disp_fields);
546 ads_destroy(&ads);
547 return 0;
549 return net_run_function(argc, argv, func, net_ads_group_usage);
552 static int net_ads_status(int argc, const char **argv)
554 ADS_STRUCT *ads;
555 ADS_STATUS rc;
556 void *res;
558 if (!(ads = ads_startup())) return -1;
560 rc = ads_find_machine_acct(ads, &res, global_myname());
561 if (!ADS_ERR_OK(rc)) {
562 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
563 return -1;
566 if (ads_count_replies(ads, res) == 0) {
567 d_printf("No machine account for '%s' found\n", global_myname());
568 return -1;
571 ads_dump(ads, res);
573 return 0;
576 static int net_ads_leave(int argc, const char **argv)
578 ADS_STRUCT *ads = NULL;
579 ADS_STATUS rc;
581 if (!secrets_init()) {
582 DEBUG(1,("Failed to initialise secrets database\n"));
583 return -1;
586 if (!opt_password) {
587 net_use_machine_password();
590 if (!(ads = ads_startup())) {
591 return -1;
594 rc = ads_leave_realm(ads, global_myname());
595 if (!ADS_ERR_OK(rc)) {
596 d_printf("Failed to delete host '%s' from the '%s' realm.\n",
597 global_myname(), ads->config.realm);
598 return -1;
601 d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
603 return 0;
606 static int net_ads_join_ok(void)
608 ADS_STRUCT *ads = NULL;
610 if (!secrets_init()) {
611 DEBUG(1,("Failed to initialise secrets database\n"));
612 return -1;
615 net_use_machine_password();
617 if (!(ads = ads_startup())) {
618 return -1;
621 ads_destroy(&ads);
622 return 0;
626 check that an existing join is OK
628 int net_ads_testjoin(int argc, const char **argv)
630 use_in_memory_ccache();
632 /* Display success or failure */
633 if (net_ads_join_ok() != 0) {
634 fprintf(stderr,"Join to domain is not valid\n");
635 return -1;
638 printf("Join is OK\n");
639 return 0;
643 join a domain using ADS
645 int net_ads_join(int argc, const char **argv)
647 ADS_STRUCT *ads;
648 ADS_STATUS rc;
649 char *password;
650 char *machine_account = NULL;
651 char *tmp_password;
652 const char *org_unit = "Computers";
653 char *dn;
654 void *res;
655 DOM_SID dom_sid;
656 char *ou_str;
657 uint32 sec_channel_type = SEC_CHAN_WKSTA;
658 uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT;
659 const char *short_domain_name = NULL;
660 TALLOC_CTX *ctx = NULL;
662 if (argc > 0) org_unit = argv[0];
664 if (!secrets_init()) {
665 DEBUG(1,("Failed to initialise secrets database\n"));
666 return -1;
669 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
670 password = strdup(tmp_password);
672 if (!(ads = ads_startup())) return -1;
674 if (!*lp_realm()) {
675 d_printf("realm must be set in in smb.conf for ADS join to succeed.\n");
676 return -1;
679 if (strcmp(ads->config.realm, lp_realm()) != 0) {
680 d_printf("realm of remote server (%s) and realm in smb.conf (%s) DO NOT match. Aborting join\n", ads->config.realm, lp_realm());
681 return -1;
684 ou_str = ads_ou_string(org_unit);
685 asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
686 free(ou_str);
688 rc = ads_search_dn(ads, &res, dn, NULL);
689 ads_msgfree(ads, res);
691 if (rc.error_type == ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
692 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
693 org_unit, dn);
694 return -1;
696 free(dn);
698 if (!ADS_ERR_OK(rc)) {
699 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
700 return -1;
703 rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
704 if (!ADS_ERR_OK(rc)) {
705 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
706 return -1;
709 rc = ads_domain_sid(ads, &dom_sid);
710 if (!ADS_ERR_OK(rc)) {
711 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
712 return -1;
715 if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
716 d_printf("asprintf failed\n");
717 return -1;
720 rc = ads_set_machine_password(ads, machine_account, password);
721 if (!ADS_ERR_OK(rc)) {
722 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
723 return -1;
726 /* make sure we get the right workgroup */
728 if ( !(ctx = talloc_init("net ads join")) ) {
729 d_printf("talloc_init() failed!\n");
730 return -1;
733 rc = ads_workgroup_name(ads, ctx, &short_domain_name);
734 if ( ADS_ERR_OK(rc) ) {
735 if ( !strequal(lp_workgroup(), short_domain_name) ) {
736 d_printf("The workgroup in smb.conf does not match the short\n");
737 d_printf("domain name obtained from the server.\n");
738 d_printf("Using the name [%s] from the server.\n", short_domain_name);
739 d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
742 else
743 short_domain_name = lp_workgroup();
745 d_printf("Using short domain name -- %s\n", short_domain_name);
747 /* HACK ALRET! Store the sid and password under bother the lp_workgroup()
748 value from smb.conf and the string returned from the server. The former is
749 neede to bootstrap winbindd's first connection to the DC to get the real
750 short domain name --jerry */
752 if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
753 DEBUG(1,("Failed to save domain sid\n"));
754 return -1;
757 if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
758 DEBUG(1,("Failed to save machine password\n"));
759 return -1;
762 if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) {
763 DEBUG(1,("Failed to save domain sid\n"));
764 return -1;
767 if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) {
768 DEBUG(1,("Failed to save machine password\n"));
769 return -1;
772 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
774 SAFE_FREE(password);
775 SAFE_FREE(machine_account);
776 if ( ctx )
777 talloc_destroy(ctx);
778 return 0;
781 int net_ads_printer_usage(int argc, const char **argv)
783 d_printf(
784 "\nnet ads printer search <printer>"
785 "\n\tsearch for a printer in the directory"
786 "\nnet ads printer info <printer> <server>"
787 "\n\tlookup info in directory for printer on server"
788 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
789 "\nnet ads printer publish <printername>"
790 "\n\tpublish printer in directory"
791 "\n\t(note: printer name is required)\n"
792 "\nnet ads printer remove <printername>"
793 "\n\tremove printer from directory"
794 "\n\t(note: printer name is required)\n");
795 return -1;
798 static int net_ads_printer_search(int argc, const char **argv)
800 ADS_STRUCT *ads;
801 ADS_STATUS rc;
802 void *res = NULL;
804 if (!(ads = ads_startup()))
805 return -1;
807 rc = ads_find_printers(ads, &res);
809 if (!ADS_ERR_OK(rc)) {
810 d_printf("ads_find_printer: %s\n", ads_errstr(rc));
811 ads_msgfree(ads, res);
812 return -1;
815 if (ads_count_replies(ads, res) == 0) {
816 d_printf("No results found\n");
817 ads_msgfree(ads, res);
818 return -1;
821 ads_dump(ads, res);
822 ads_msgfree(ads, res);
824 return 0;
827 static int net_ads_printer_info(int argc, const char **argv)
829 ADS_STRUCT *ads;
830 ADS_STATUS rc;
831 const char *servername, *printername;
832 void *res = NULL;
834 if (!(ads = ads_startup())) return -1;
836 if (argc > 0)
837 printername = argv[0];
838 else
839 printername = "*";
841 if (argc > 1)
842 servername = argv[1];
843 else
844 servername = global_myname();
846 rc = ads_find_printer_on_server(ads, &res, printername, servername);
848 if (!ADS_ERR_OK(rc)) {
849 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
850 ads_msgfree(ads, res);
851 return -1;
854 if (ads_count_replies(ads, res) == 0) {
855 d_printf("Printer '%s' not found\n", printername);
856 ads_msgfree(ads, res);
857 return -1;
860 ads_dump(ads, res);
861 ads_msgfree(ads, res);
863 return 0;
866 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
868 return;
871 static int net_ads_printer_publish(int argc, const char **argv)
873 ADS_STRUCT *ads;
874 ADS_STATUS rc;
875 const char *servername, *printername;
876 struct cli_state *cli;
877 struct in_addr server_ip;
878 NTSTATUS nt_status;
879 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
880 ADS_MODLIST mods = ads_init_mods(mem_ctx);
881 char *prt_dn, *srv_dn, **srv_cn;
882 void *res = NULL;
884 if (!(ads = ads_startup())) return -1;
886 if (argc < 1)
887 return net_ads_printer_usage(argc, argv);
889 printername = argv[0];
891 if (argc == 2)
892 servername = argv[1];
893 else
894 servername = global_myname();
896 /* Get printer data from SPOOLSS */
898 resolve_name(servername, &server_ip, 0x20);
900 nt_status = cli_full_connection(&cli, global_myname(), servername,
901 &server_ip, 0,
902 "IPC$", "IPC",
903 opt_user_name, opt_workgroup,
904 opt_password ? opt_password : "",
905 CLI_FULL_CONNECTION_USE_KERBEROS,
906 Undefined, NULL);
908 if (NT_STATUS_IS_ERR(nt_status)) {
909 d_printf("Unable to open a connnection to %s to obtain data "
910 "for %s\n", servername, printername);
911 return -1;
914 /* Publish on AD server */
916 ads_find_machine_acct(ads, &res, servername);
918 if (ads_count_replies(ads, res) == 0) {
919 d_printf("Could not find machine account for server %s\n",
920 servername);
921 return -1;
924 srv_dn = ldap_get_dn(ads->ld, res);
925 srv_cn = ldap_explode_dn(srv_dn, 1);
927 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
929 cli_nt_session_open(cli, PI_SPOOLSS);
930 get_remote_printer_publishing_data(cli, mem_ctx, &mods, printername);
932 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
933 if (!ADS_ERR_OK(rc)) {
934 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
935 return -1;
938 d_printf("published printer\n");
940 return 0;
943 static int net_ads_printer_remove(int argc, const char **argv)
945 ADS_STRUCT *ads;
946 ADS_STATUS rc;
947 const char *servername;
948 char *prt_dn;
949 void *res = NULL;
951 if (!(ads = ads_startup())) return -1;
953 if (argc < 1)
954 return net_ads_printer_usage(argc, argv);
956 if (argc > 1)
957 servername = argv[1];
958 else
959 servername = global_myname();
961 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
963 if (!ADS_ERR_OK(rc)) {
964 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
965 ads_msgfree(ads, res);
966 return -1;
969 if (ads_count_replies(ads, res) == 0) {
970 d_printf("Printer '%s' not found\n", argv[1]);
971 ads_msgfree(ads, res);
972 return -1;
975 prt_dn = ads_get_dn(ads, res);
976 ads_msgfree(ads, res);
977 rc = ads_del_dn(ads, prt_dn);
978 ads_memfree(ads, prt_dn);
980 if (!ADS_ERR_OK(rc)) {
981 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
982 return -1;
985 return 0;
988 static int net_ads_printer(int argc, const char **argv)
990 struct functable func[] = {
991 {"SEARCH", net_ads_printer_search},
992 {"INFO", net_ads_printer_info},
993 {"PUBLISH", net_ads_printer_publish},
994 {"REMOVE", net_ads_printer_remove},
995 {NULL, NULL}
998 return net_run_function(argc, argv, func, net_ads_printer_usage);
1002 static int net_ads_password(int argc, const char **argv)
1004 ADS_STRUCT *ads;
1005 const char *auth_principal = opt_user_name;
1006 const char *auth_password = opt_password;
1007 char *realm = NULL;
1008 char *new_password = NULL;
1009 char *c, *prompt;
1010 const char *user;
1011 ADS_STATUS ret;
1013 if (opt_user_name == NULL || opt_password == NULL) {
1014 d_printf("You must supply an administrator username/password\n");
1015 return -1;
1019 if (argc != 1) {
1020 d_printf("ERROR: You must say which username to change password for\n");
1021 return -1;
1024 user = argv[0];
1025 if (!strchr(user, '@')) {
1026 asprintf(&c, "%s@%s", argv[0], lp_realm());
1027 user = c;
1030 use_in_memory_ccache();
1031 c = strchr(auth_principal, '@');
1032 if (c) {
1033 realm = ++c;
1034 } else {
1035 realm = lp_realm();
1038 /* use the realm so we can eventually change passwords for users
1039 in realms other than default */
1040 if (!(ads = ads_init(realm, NULL, NULL))) return -1;
1042 /* we don't actually need a full connect, but it's the easy way to
1043 fill in the KDC's addresss */
1044 ads_connect(ads);
1046 if (!ads || !ads->config.realm) {
1047 d_printf("Didn't find the kerberos server!\n");
1048 return -1;
1051 asprintf(&prompt, "Enter new password for %s:", user);
1053 new_password = getpass(prompt);
1055 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1056 auth_password, user, new_password, ads->auth.time_offset);
1057 if (!ADS_ERR_OK(ret)) {
1058 d_printf("Password change failed :-( ...\n");
1059 ads_destroy(&ads);
1060 free(prompt);
1061 return -1;
1064 d_printf("Password change for %s completed.\n", user);
1065 ads_destroy(&ads);
1066 free(prompt);
1068 return 0;
1072 int net_ads_changetrustpw(int argc, const char **argv)
1074 ADS_STRUCT *ads;
1075 char *host_principal;
1076 char *hostname;
1077 ADS_STATUS ret;
1079 if (!secrets_init()) {
1080 DEBUG(1,("Failed to initialise secrets database\n"));
1081 return -1;
1084 net_use_machine_password();
1086 use_in_memory_ccache();
1088 if (!(ads = ads_startup())) {
1089 return -1;
1092 hostname = strdup(global_myname());
1093 strlower_m(hostname);
1094 asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
1095 SAFE_FREE(hostname);
1096 d_printf("Changing password for principal: HOST/%s\n", host_principal);
1098 ret = ads_change_trust_account_password(ads, host_principal);
1100 if (!ADS_ERR_OK(ret)) {
1101 d_printf("Password change failed :-( ...\n");
1102 ads_destroy(&ads);
1103 SAFE_FREE(host_principal);
1104 return -1;
1107 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
1108 ads_destroy(&ads);
1109 SAFE_FREE(host_principal);
1111 return 0;
1115 help for net ads search
1117 static int net_ads_search_usage(int argc, const char **argv)
1119 d_printf(
1120 "\nnet ads search <expression> <attributes...>\n"\
1121 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1122 "The expression is a standard LDAP search expression, and the\n"\
1123 "attributes are a list of LDAP fields to show in the results\n\n"\
1124 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1126 net_common_flags_usage(argc, argv);
1127 return -1;
1132 general ADS search function. Useful in diagnosing problems in ADS
1134 static int net_ads_search(int argc, const char **argv)
1136 ADS_STRUCT *ads;
1137 ADS_STATUS rc;
1138 const char *ldap_exp;
1139 const char **attrs;
1140 void *res = NULL;
1142 if (argc < 1) {
1143 return net_ads_search_usage(argc, argv);
1146 if (!(ads = ads_startup())) {
1147 return -1;
1150 ldap_exp = argv[0];
1151 attrs = (argv + 1);
1153 rc = ads_do_search_all(ads, ads->config.bind_path,
1154 LDAP_SCOPE_SUBTREE,
1155 ldap_exp, attrs, &res);
1156 if (!ADS_ERR_OK(rc)) {
1157 d_printf("search failed: %s\n", ads_errstr(rc));
1158 return -1;
1161 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1163 /* dump the results */
1164 ads_dump(ads, res);
1166 ads_msgfree(ads, res);
1167 ads_destroy(&ads);
1169 return 0;
1174 help for net ads search
1176 static int net_ads_dn_usage(int argc, const char **argv)
1178 d_printf(
1179 "\nnet ads dn <dn> <attributes...>\n"\
1180 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1181 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1182 "to show in the results\n\n"\
1183 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1185 net_common_flags_usage(argc, argv);
1186 return -1;
1191 general ADS search function. Useful in diagnosing problems in ADS
1193 static int net_ads_dn(int argc, const char **argv)
1195 ADS_STRUCT *ads;
1196 ADS_STATUS rc;
1197 const char *dn;
1198 const char **attrs;
1199 void *res = NULL;
1201 if (argc < 1) {
1202 return net_ads_dn_usage(argc, argv);
1205 if (!(ads = ads_startup())) {
1206 return -1;
1209 dn = argv[0];
1210 attrs = (argv + 1);
1212 rc = ads_do_search_all(ads, dn,
1213 LDAP_SCOPE_BASE,
1214 "(objectclass=*)", attrs, &res);
1215 if (!ADS_ERR_OK(rc)) {
1216 d_printf("search failed: %s\n", ads_errstr(rc));
1217 return -1;
1220 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1222 /* dump the results */
1223 ads_dump(ads, res);
1225 ads_msgfree(ads, res);
1226 ads_destroy(&ads);
1228 return 0;
1232 int net_ads_help(int argc, const char **argv)
1234 struct functable func[] = {
1235 {"USER", net_ads_user_usage},
1236 {"GROUP", net_ads_group_usage},
1237 {"PRINTER", net_ads_printer_usage},
1238 {"SEARCH", net_ads_search_usage},
1239 #if 0
1240 {"INFO", net_ads_info},
1241 {"JOIN", net_ads_join},
1242 {"LEAVE", net_ads_leave},
1243 {"STATUS", net_ads_status},
1244 {"PASSWORD", net_ads_password},
1245 {"CHANGETRUSTPW", net_ads_changetrustpw},
1246 #endif
1247 {NULL, NULL}
1250 return net_run_function(argc, argv, func, net_ads_usage);
1253 int net_ads(int argc, const char **argv)
1255 struct functable func[] = {
1256 {"INFO", net_ads_info},
1257 {"JOIN", net_ads_join},
1258 {"TESTJOIN", net_ads_testjoin},
1259 {"LEAVE", net_ads_leave},
1260 {"STATUS", net_ads_status},
1261 {"USER", net_ads_user},
1262 {"GROUP", net_ads_group},
1263 {"PASSWORD", net_ads_password},
1264 {"CHANGETRUSTPW", net_ads_changetrustpw},
1265 {"PRINTER", net_ads_printer},
1266 {"SEARCH", net_ads_search},
1267 {"DN", net_ads_dn},
1268 {"WORKGROUP", net_ads_workgroup},
1269 {"LOOKUP", net_ads_lookup},
1270 {"HELP", net_ads_help},
1271 {NULL, NULL}
1274 return net_run_function(argc, argv, func, net_ads_usage);
1277 #else
1279 static int net_ads_noads(void)
1281 d_printf("ADS support not compiled in\n");
1282 return -1;
1285 int net_ads_usage(int argc, const char **argv)
1287 return net_ads_noads();
1290 int net_ads_help(int argc, const char **argv)
1292 return net_ads_noads();
1295 int net_ads_changetrustpw(int argc, const char **argv)
1297 return net_ads_noads();
1300 int net_ads_join(int argc, const char **argv)
1302 return net_ads_noads();
1305 int net_ads_user(int argc, const char **argv)
1307 return net_ads_noads();
1310 int net_ads_group(int argc, const char **argv)
1312 return net_ads_noads();
1315 /* this one shouldn't display a message */
1316 int net_ads_check(void)
1318 return -1;
1321 int net_ads(int argc, const char **argv)
1323 return net_ads_usage(argc, argv);
1326 #endif