Patch from Ken Cross to allow an ADS domain join with a username of the form
[Samba.git] / source / utils / net_ads.c
blob1a50f9d27073ad95e3cab1bfeb2d21fd7cbaceca
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, NULL, 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, NULL, 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 ads = ads_init(NULL, NULL, opt_host);
134 if (!opt_user_name) {
135 opt_user_name = "administrator";
138 if (opt_user_specified) {
139 need_password = True;
142 retry:
143 if (!opt_password && need_password) {
144 char *prompt;
145 asprintf(&prompt,"%s password: ", opt_user_name);
146 opt_password = getpass(prompt);
147 free(prompt);
150 if (opt_password) {
151 use_in_memory_ccache();
152 ads->auth.password = smb_xstrdup(opt_password);
155 ads->auth.user_name = smb_xstrdup(opt_user_name);
158 * If the username is of the form "name@realm",
159 * extract the realm and convert to upper case.
160 * This is only used to establish the connection.
162 if (cp = strchr(ads->auth.user_name, '@')) {
163 *cp++ = '\0';
164 ads->auth.realm = smb_xstrdup(cp);
165 strupper(ads->auth.realm);
168 status = ads_connect(ads);
170 if (!ADS_ERR_OK(status)) {
171 if (!need_password && !second_time) {
172 need_password = True;
173 second_time = True;
174 goto retry;
175 } else {
176 DEBUG(1,("ads_connect: %s\n", ads_errstr(status)));
177 return NULL;
180 return ads;
185 Check to see if connection can be made via ads.
186 ads_startup() stores the password in opt_password if it needs to so
187 that rpc or rap can use it without re-prompting.
189 int net_ads_check(void)
191 ADS_STRUCT *ads;
193 ads = ads_startup();
194 if (!ads)
195 return -1;
196 ads_destroy(&ads);
197 return 0;
201 determine the netbios workgroup name for a domain
203 static int net_ads_workgroup(int argc, const char **argv)
205 ADS_STRUCT *ads;
206 TALLOC_CTX *ctx;
207 char *workgroup;
209 if (!(ads = ads_startup())) return -1;
211 if (!(ctx = talloc_init("net_ads_workgroup"))) {
212 return -1;
215 if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
216 d_printf("Failed to find workgroup for realm '%s'\n",
217 ads->config.realm);
218 talloc_destroy(ctx);
219 return -1;
222 d_printf("Workgroup: %s\n", workgroup);
224 talloc_destroy(ctx);
226 return 0;
231 static BOOL usergrp_display(char *field, void **values, void *data_area)
233 char **disp_fields = (char **) data_area;
235 if (!field) { /* must be end of record */
236 if (!strchr_m(disp_fields[0], '$')) {
237 if (disp_fields[1])
238 d_printf("%-21.21s %s\n",
239 disp_fields[0], disp_fields[1]);
240 else
241 d_printf("%s\n", disp_fields[0]);
243 SAFE_FREE(disp_fields[0]);
244 SAFE_FREE(disp_fields[1]);
245 return True;
247 if (!values) /* must be new field, indicate string field */
248 return True;
249 if (StrCaseCmp(field, "sAMAccountName") == 0) {
250 disp_fields[0] = strdup((char *) values[0]);
252 if (StrCaseCmp(field, "description") == 0)
253 disp_fields[1] = strdup((char *) values[0]);
254 return True;
257 static int net_ads_user_usage(int argc, const char **argv)
259 return net_help_user(argc, argv);
262 static int ads_user_add(int argc, const char **argv)
264 ADS_STRUCT *ads;
265 ADS_STATUS status;
266 char *upn, *userdn;
267 void *res=NULL;
268 int rc = -1;
270 if (argc < 1) return net_ads_user_usage(argc, argv);
272 if (!(ads = ads_startup())) return -1;
274 status = ads_find_user_acct(ads, &res, argv[0]);
276 if (!ADS_ERR_OK(status)) {
277 d_printf("ads_user_add: %s\n", ads_errstr(status));
278 goto done;
281 if (ads_count_replies(ads, res)) {
282 d_printf("ads_user_add: User %s already exists\n", argv[0]);
283 goto done;
286 status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
288 if (!ADS_ERR_OK(status)) {
289 d_printf("Could not add user %s: %s\n", argv[0],
290 ads_errstr(status));
291 goto done;
294 /* if no password is to be set, we're done */
295 if (argc == 1) {
296 d_printf("User %s added\n", argv[0]);
297 rc = 0;
298 goto done;
301 /* try setting the password */
302 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
303 status = krb5_set_password(ads->auth.kdc_server, upn, argv[1], ads->auth.time_offset);
304 safe_free(upn);
305 if (ADS_ERR_OK(status)) {
306 d_printf("User %s added\n", argv[0]);
307 rc = 0;
308 goto done;
311 /* password didn't set, delete account */
312 d_printf("Could not add user %s. Error setting password %s\n",
313 argv[0], ads_errstr(status));
314 ads_msgfree(ads, res);
315 status=ads_find_user_acct(ads, &res, argv[0]);
316 if (ADS_ERR_OK(status)) {
317 userdn = ads_get_dn(ads, res);
318 ads_del_dn(ads, userdn);
319 ads_memfree(ads, userdn);
322 done:
323 if (res)
324 ads_msgfree(ads, res);
325 ads_destroy(&ads);
326 return rc;
329 static int ads_user_info(int argc, const char **argv)
331 ADS_STRUCT *ads;
332 ADS_STATUS rc;
333 void *res;
334 const char *attrs[] = {"memberOf", NULL};
335 char *searchstring=NULL;
336 char **grouplist;
337 char *escaped_user = escape_ldap_string_alloc(argv[0]);
339 if (argc < 1) return net_ads_user_usage(argc, argv);
341 if (!(ads = ads_startup())) return -1;
343 if (!escaped_user) {
344 d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
345 return -1;
348 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
349 rc = ads_search(ads, &res, searchstring, attrs);
350 safe_free(searchstring);
352 if (!ADS_ERR_OK(rc)) {
353 d_printf("ads_search: %s\n", ads_errstr(rc));
354 return -1;
357 grouplist = ldap_get_values(ads->ld, res, "memberOf");
359 if (grouplist) {
360 int i;
361 char **groupname;
362 for (i=0;grouplist[i];i++) {
363 groupname = ldap_explode_dn(grouplist[i], 1);
364 d_printf("%s\n", groupname[0]);
365 ldap_value_free(groupname);
367 ldap_value_free(grouplist);
370 ads_msgfree(ads, res);
372 ads_destroy(&ads);
373 return 0;
376 static int ads_user_delete(int argc, const char **argv)
378 ADS_STRUCT *ads;
379 ADS_STATUS rc;
380 void *res;
381 char *userdn;
383 if (argc < 1) return net_ads_user_usage(argc, argv);
385 if (!(ads = ads_startup())) return -1;
387 rc = ads_find_user_acct(ads, &res, argv[0]);
388 if (!ADS_ERR_OK(rc)) {
389 DEBUG(0, ("User %s does not exist\n", argv[0]));
390 return -1;
392 userdn = ads_get_dn(ads, res);
393 ads_msgfree(ads, res);
394 rc = ads_del_dn(ads, userdn);
395 ads_memfree(ads, userdn);
396 if (!ADS_ERR_OK(rc)) {
397 d_printf("User %s deleted\n", argv[0]);
398 return 0;
400 d_printf("Error deleting user %s: %s\n", argv[0],
401 ads_errstr(rc));
402 return -1;
405 int net_ads_user(int argc, const char **argv)
407 struct functable func[] = {
408 {"ADD", ads_user_add},
409 {"INFO", ads_user_info},
410 {"DELETE", ads_user_delete},
411 {NULL, NULL}
413 ADS_STRUCT *ads;
414 ADS_STATUS rc;
415 const char *shortattrs[] = {"sAMAccountName", NULL};
416 const char *longattrs[] = {"sAMAccountName", "description", NULL};
417 char *disp_fields[2] = {NULL, NULL};
419 if (argc == 0) {
420 if (!(ads = ads_startup())) return -1;
422 if (opt_long_list_entries)
423 d_printf("\nUser name Comment"\
424 "\n-----------------------------\n");
426 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
427 LDAP_SCOPE_SUBTREE,
428 "(objectclass=user)",
429 opt_long_list_entries ? longattrs :
430 shortattrs, usergrp_display,
431 disp_fields);
432 ads_destroy(&ads);
433 return 0;
436 return net_run_function(argc, argv, func, net_ads_user_usage);
439 static int net_ads_group_usage(int argc, const char **argv)
441 return net_help_group(argc, argv);
444 static int ads_group_add(int argc, const char **argv)
446 ADS_STRUCT *ads;
447 ADS_STATUS status;
448 void *res=NULL;
449 int rc = -1;
451 if (argc < 1) return net_ads_group_usage(argc, argv);
453 if (!(ads = ads_startup())) return -1;
455 status = ads_find_user_acct(ads, &res, argv[0]);
457 if (!ADS_ERR_OK(status)) {
458 d_printf("ads_group_add: %s\n", ads_errstr(status));
459 goto done;
462 if (ads_count_replies(ads, res)) {
463 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
464 ads_msgfree(ads, res);
465 goto done;
468 status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
470 if (ADS_ERR_OK(status)) {
471 d_printf("Group %s added\n", argv[0]);
472 rc = 0;
473 } else {
474 d_printf("Could not add group %s: %s\n", argv[0],
475 ads_errstr(status));
478 done:
479 if (res)
480 ads_msgfree(ads, res);
481 ads_destroy(&ads);
482 return rc;
485 static int ads_group_delete(int argc, const char **argv)
487 ADS_STRUCT *ads;
488 ADS_STATUS rc;
489 void *res;
490 char *groupdn;
492 if (argc < 1) return net_ads_group_usage(argc, argv);
494 if (!(ads = ads_startup())) return -1;
496 rc = ads_find_user_acct(ads, &res, argv[0]);
497 if (!ADS_ERR_OK(rc)) {
498 DEBUG(0, ("Group %s does not exist\n", argv[0]));
499 return -1;
501 groupdn = ads_get_dn(ads, res);
502 ads_msgfree(ads, res);
503 rc = ads_del_dn(ads, groupdn);
504 ads_memfree(ads, groupdn);
505 if (!ADS_ERR_OK(rc)) {
506 d_printf("Group %s deleted\n", argv[0]);
507 return 0;
509 d_printf("Error deleting group %s: %s\n", argv[0],
510 ads_errstr(rc));
511 return -1;
514 int net_ads_group(int argc, const char **argv)
516 struct functable func[] = {
517 {"ADD", ads_group_add},
518 {"DELETE", ads_group_delete},
519 {NULL, NULL}
521 ADS_STRUCT *ads;
522 ADS_STATUS rc;
523 const char *shortattrs[] = {"sAMAccountName", NULL};
524 const char *longattrs[] = {"sAMAccountName", "description", NULL};
525 char *disp_fields[2] = {NULL, NULL};
527 if (argc == 0) {
528 if (!(ads = ads_startup())) return -1;
530 if (opt_long_list_entries)
531 d_printf("\nGroup name Comment"\
532 "\n-----------------------------\n");
533 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
534 LDAP_SCOPE_SUBTREE,
535 "(objectclass=group)",
536 opt_long_list_entries ? longattrs :
537 shortattrs, usergrp_display,
538 disp_fields);
540 ads_destroy(&ads);
541 return 0;
543 return net_run_function(argc, argv, func, net_ads_group_usage);
546 static int net_ads_status(int argc, const char **argv)
548 ADS_STRUCT *ads;
549 ADS_STATUS rc;
550 void *res;
552 if (!(ads = ads_startup())) return -1;
554 rc = ads_find_machine_acct(ads, &res, global_myname());
555 if (!ADS_ERR_OK(rc)) {
556 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
557 return -1;
560 if (ads_count_replies(ads, res) == 0) {
561 d_printf("No machine account for '%s' found\n", global_myname());
562 return -1;
565 ads_dump(ads, res);
567 return 0;
570 static int net_ads_leave(int argc, const char **argv)
572 ADS_STRUCT *ads = NULL;
573 ADS_STATUS rc;
575 if (!secrets_init()) {
576 DEBUG(1,("Failed to initialise secrets database\n"));
577 return -1;
580 if (!opt_password) {
581 char *user_name;
582 asprintf(&user_name, "%s$", global_myname());
583 opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL);
584 opt_user_name = user_name;
587 if (!(ads = ads_startup())) {
588 return -1;
591 rc = ads_leave_realm(ads, global_myname());
592 if (!ADS_ERR_OK(rc)) {
593 d_printf("Failed to delete host '%s' from the '%s' realm.\n",
594 global_myname(), ads->config.realm);
595 return -1;
598 d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
600 return 0;
603 static int net_ads_join_ok(void)
605 char *user_name;
606 ADS_STRUCT *ads = NULL;
608 if (!secrets_init()) {
609 DEBUG(1,("Failed to initialise secrets database\n"));
610 return -1;
613 asprintf(&user_name, "%s$", global_myname());
614 opt_user_name = user_name;
615 opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL);
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 *tmp_password;
651 const char *org_unit = "Computers";
652 char *dn;
653 void *res;
654 DOM_SID dom_sid;
655 char *ou_str;
656 uint32 sec_channel_type = SEC_CHAN_WKSTA;
657 uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT;
659 if (argc > 0) org_unit = argv[0];
661 if (!secrets_init()) {
662 DEBUG(1,("Failed to initialise secrets database\n"));
663 return -1;
666 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
667 password = strdup(tmp_password);
669 if (!(ads = ads_startup())) return -1;
671 ou_str = ads_ou_string(org_unit);
672 asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
673 free(ou_str);
675 rc = ads_search_dn(ads, &res, dn, NULL);
676 ads_msgfree(ads, res);
678 if (rc.error_type == ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
679 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
680 org_unit, dn);
681 return -1;
683 free(dn);
685 if (!ADS_ERR_OK(rc)) {
686 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
687 return -1;
690 rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
691 if (!ADS_ERR_OK(rc)) {
692 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
693 return -1;
696 rc = ads_domain_sid(ads, &dom_sid);
697 if (!ADS_ERR_OK(rc)) {
698 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
699 return -1;
702 rc = ads_set_machine_password(ads, global_myname(), password);
703 if (!ADS_ERR_OK(rc)) {
704 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
705 return -1;
708 if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
709 DEBUG(1,("Failed to save domain sid\n"));
710 return -1;
713 if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
714 DEBUG(1,("Failed to save machine password\n"));
715 return -1;
718 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
720 free(password);
722 return 0;
725 int net_ads_printer_usage(int argc, const char **argv)
727 d_printf(
728 "\nnet ads printer info <printer> <server>"
729 "\n\tlookup info in directory for printer on server"
730 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
731 "\nnet ads printer publish <printername>"
732 "\n\tpublish printer in directory"
733 "\n\t(note: printer name is required)\n"
734 "\nnet ads printer remove <printername>"
735 "\n\tremove printer from directory"
736 "\n\t(note: printer name is required)\n");
737 return -1;
740 static int net_ads_printer_info(int argc, const char **argv)
742 ADS_STRUCT *ads;
743 ADS_STATUS rc;
744 const char *servername, *printername;
745 void *res = NULL;
747 if (!(ads = ads_startup())) return -1;
749 if (argc > 0)
750 printername = argv[0];
751 else
752 printername = "*";
754 if (argc > 1)
755 servername = argv[1];
756 else
757 servername = global_myname();
759 rc = ads_find_printer_on_server(ads, &res, printername, servername);
761 if (!ADS_ERR_OK(rc)) {
762 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
763 ads_msgfree(ads, res);
764 return -1;
767 if (ads_count_replies(ads, res) == 0) {
768 d_printf("Printer '%s' not found\n", printername);
769 ads_msgfree(ads, res);
770 return -1;
773 ads_dump(ads, res);
774 ads_msgfree(ads, res);
776 return 0;
779 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
781 return;
784 static int net_ads_printer_publish(int argc, const char **argv)
786 ADS_STRUCT *ads;
787 ADS_STATUS rc;
788 const char *servername;
789 struct cli_state *cli;
790 struct in_addr server_ip;
791 NTSTATUS nt_status;
792 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
793 ADS_MODLIST mods = ads_init_mods(mem_ctx);
794 char *prt_dn, *srv_dn, **srv_cn;
795 void *res = NULL;
797 if (!(ads = ads_startup())) return -1;
799 if (argc < 1)
800 return net_ads_printer_usage(argc, argv);
802 if (argc == 2)
803 servername = argv[1];
804 else
805 servername = global_myname();
807 ads_find_machine_acct(ads, &res, servername);
808 srv_dn = ldap_get_dn(ads->ld, res);
809 srv_cn = ldap_explode_dn(srv_dn, 1);
810 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], argv[0], srv_dn);
812 resolve_name(servername, &server_ip, 0x20);
814 nt_status = cli_full_connection(&cli, global_myname(), servername,
815 &server_ip, 0,
816 "IPC$", "IPC",
817 opt_user_name, opt_workgroup,
818 opt_password ? opt_password : "",
819 CLI_FULL_CONNECTION_USE_KERBEROS,
820 NULL);
822 cli_nt_session_open(cli, PI_SPOOLSS);
823 get_remote_printer_publishing_data(cli, mem_ctx, &mods, argv[0]);
825 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
826 if (!ADS_ERR_OK(rc)) {
827 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
828 return -1;
831 d_printf("published printer\n");
833 return 0;
836 static int net_ads_printer_remove(int argc, const char **argv)
838 ADS_STRUCT *ads;
839 ADS_STATUS rc;
840 const char *servername;
841 char *prt_dn;
842 void *res = NULL;
844 if (!(ads = ads_startup())) return -1;
846 if (argc < 1)
847 return net_ads_printer_usage(argc, argv);
849 if (argc > 1)
850 servername = argv[1];
851 else
852 servername = global_myname();
854 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
856 if (!ADS_ERR_OK(rc)) {
857 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
858 ads_msgfree(ads, res);
859 return -1;
862 if (ads_count_replies(ads, res) == 0) {
863 d_printf("Printer '%s' not found\n", argv[1]);
864 ads_msgfree(ads, res);
865 return -1;
868 prt_dn = ads_get_dn(ads, res);
869 ads_msgfree(ads, res);
870 rc = ads_del_dn(ads, prt_dn);
871 ads_memfree(ads, prt_dn);
873 if (!ADS_ERR_OK(rc)) {
874 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
875 return -1;
878 return 0;
881 static int net_ads_printer(int argc, const char **argv)
883 struct functable func[] = {
884 {"INFO", net_ads_printer_info},
885 {"PUBLISH", net_ads_printer_publish},
886 {"REMOVE", net_ads_printer_remove},
887 {NULL, NULL}
890 return net_run_function(argc, argv, func, net_ads_printer_usage);
894 static int net_ads_password(int argc, const char **argv)
896 ADS_STRUCT *ads;
897 const char *auth_principal = opt_user_name;
898 const char *auth_password = opt_password;
899 char *realm = NULL;
900 char *new_password = NULL;
901 char *c;
902 char *prompt;
903 ADS_STATUS ret;
906 if ((argc != 1) || (opt_user_name == NULL) ||
907 (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
908 (strchr(argv[0], '@') == NULL)) {
909 return net_ads_usage(argc, argv);
912 use_in_memory_ccache();
913 c = strchr(auth_principal, '@');
914 realm = ++c;
916 /* use the realm so we can eventually change passwords for users
917 in realms other than default */
918 if (!(ads = ads_init(realm, NULL, NULL))) return -1;
920 /* we don't actually need a full connect, but it's the easy way to
921 fill in the KDC's addresss */
922 ads_connect(ads);
924 if (!ads || !ads->config.realm) {
925 d_printf("Didn't find the kerberos server!\n");
926 return -1;
929 asprintf(&prompt, "Enter new password for %s:", argv[0]);
931 new_password = getpass(prompt);
933 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
934 auth_password, argv[0], new_password, ads->auth.time_offset);
935 if (!ADS_ERR_OK(ret)) {
936 d_printf("Password change failed :-( ...\n");
937 ads_destroy(&ads);
938 free(prompt);
939 return -1;
942 d_printf("Password change for %s completed.\n", argv[0]);
943 ads_destroy(&ads);
944 free(prompt);
946 return 0;
950 int net_ads_changetrustpw(int argc, const char **argv)
952 ADS_STRUCT *ads;
953 char *host_principal;
954 char *hostname;
955 ADS_STATUS ret;
956 char *user_name;
958 if (!secrets_init()) {
959 DEBUG(1,("Failed to initialise secrets database\n"));
960 return -1;
963 asprintf(&user_name, "%s$", global_myname());
964 opt_user_name = user_name;
966 opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL);
968 use_in_memory_ccache();
970 if (!(ads = ads_startup())) {
971 return -1;
974 hostname = strdup(global_myname());
975 strlower(hostname);
976 asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
977 SAFE_FREE(hostname);
978 d_printf("Changing password for principal: HOST/%s\n", host_principal);
980 ret = ads_change_trust_account_password(ads, host_principal);
982 if (!ADS_ERR_OK(ret)) {
983 d_printf("Password change failed :-( ...\n");
984 ads_destroy(&ads);
985 SAFE_FREE(host_principal);
986 return -1;
989 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
990 ads_destroy(&ads);
991 SAFE_FREE(host_principal);
993 return 0;
997 help for net ads search
999 static int net_ads_search_usage(int argc, const char **argv)
1001 d_printf(
1002 "\nnet ads search <expression> <attributes...>\n"\
1003 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1004 "The expression is a standard LDAP search expression, and the\n"\
1005 "attributes are a list of LDAP fields to show in the results\n\n"\
1006 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1008 net_common_flags_usage(argc, argv);
1009 return -1;
1014 general ADS search function. Useful in diagnosing problems in ADS
1016 static int net_ads_search(int argc, const char **argv)
1018 ADS_STRUCT *ads;
1019 ADS_STATUS rc;
1020 const char *exp;
1021 const char **attrs;
1022 void *res = NULL;
1024 if (argc < 1) {
1025 return net_ads_search_usage(argc, argv);
1028 if (!(ads = ads_startup())) {
1029 return -1;
1032 exp = argv[0];
1033 attrs = (argv + 1);
1035 rc = ads_do_search_all(ads, ads->config.bind_path,
1036 LDAP_SCOPE_SUBTREE,
1037 exp, attrs, &res);
1038 if (!ADS_ERR_OK(rc)) {
1039 d_printf("search failed: %s\n", ads_errstr(rc));
1040 return -1;
1043 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1045 /* dump the results */
1046 ads_dump(ads, res);
1048 ads_msgfree(ads, res);
1049 ads_destroy(&ads);
1051 return 0;
1056 help for net ads search
1058 static int net_ads_dn_usage(int argc, const char **argv)
1060 d_printf(
1061 "\nnet ads dn <dn> <attributes...>\n"\
1062 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1063 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1064 "to show in the results\n\n"\
1065 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1067 net_common_flags_usage(argc, argv);
1068 return -1;
1073 general ADS search function. Useful in diagnosing problems in ADS
1075 static int net_ads_dn(int argc, const char **argv)
1077 ADS_STRUCT *ads;
1078 ADS_STATUS rc;
1079 const char *dn;
1080 const char **attrs;
1081 void *res = NULL;
1083 if (argc < 1) {
1084 return net_ads_dn_usage(argc, argv);
1087 if (!(ads = ads_startup())) {
1088 return -1;
1091 dn = argv[0];
1092 attrs = (argv + 1);
1094 rc = ads_do_search_all(ads, dn,
1095 LDAP_SCOPE_BASE,
1096 "(objectclass=*)", attrs, &res);
1097 if (!ADS_ERR_OK(rc)) {
1098 d_printf("search failed: %s\n", ads_errstr(rc));
1099 return -1;
1102 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1104 /* dump the results */
1105 ads_dump(ads, res);
1107 ads_msgfree(ads, res);
1108 ads_destroy(&ads);
1110 return 0;
1114 int net_ads_help(int argc, const char **argv)
1116 struct functable func[] = {
1117 {"USER", net_ads_user_usage},
1118 {"GROUP", net_ads_group_usage},
1119 {"PRINTER", net_ads_printer_usage},
1120 {"SEARCH", net_ads_search_usage},
1121 #if 0
1122 {"INFO", net_ads_info},
1123 {"JOIN", net_ads_join},
1124 {"LEAVE", net_ads_leave},
1125 {"STATUS", net_ads_status},
1126 {"PASSWORD", net_ads_password},
1127 {"CHANGETRUSTPW", net_ads_changetrustpw},
1128 #endif
1129 {NULL, NULL}
1132 return net_run_function(argc, argv, func, net_ads_usage);
1135 int net_ads(int argc, const char **argv)
1137 struct functable func[] = {
1138 {"INFO", net_ads_info},
1139 {"JOIN", net_ads_join},
1140 {"TESTJOIN", net_ads_testjoin},
1141 {"LEAVE", net_ads_leave},
1142 {"STATUS", net_ads_status},
1143 {"USER", net_ads_user},
1144 {"GROUP", net_ads_group},
1145 {"PASSWORD", net_ads_password},
1146 {"CHANGETRUSTPW", net_ads_changetrustpw},
1147 {"PRINTER", net_ads_printer},
1148 {"SEARCH", net_ads_search},
1149 {"DN", net_ads_dn},
1150 {"WORKGROUP", net_ads_workgroup},
1151 {"LOOKUP", net_ads_lookup},
1152 {"HELP", net_ads_help},
1153 {NULL, NULL}
1156 return net_run_function(argc, argv, func, net_ads_usage);
1159 #else
1161 static int net_ads_noads(void)
1163 d_printf("ADS support not compiled in\n");
1164 return -1;
1167 int net_ads_usage(int argc, const char **argv)
1169 return net_ads_noads();
1172 int net_ads_help(int argc, const char **argv)
1174 return net_ads_noads();
1177 int net_ads_changetrustpw(int argc, const char **argv)
1179 return net_ads_noads();
1182 int net_ads_join(int argc, const char **argv)
1184 return net_ads_noads();
1187 int net_ads_user(int argc, const char **argv)
1189 return net_ads_noads();
1192 int net_ads_group(int argc, const char **argv)
1194 return net_ads_noads();
1197 /* this one shouldn't display a message */
1198 int net_ads_check(void)
1200 return -1;
1203 int net_ads(int argc, const char **argv)
1205 return net_ads_usage(argc, argv);
1208 #endif