port latest changes from SAMBA_3_0 tree
[Samba.git] / source3 / utils / net_ads.c
blob631e235127559a6d06c035e5f8ab05da413eab8a
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 ads = ads_init(NULL, opt_target_workgroup, 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, '@'))!=0) {
163 *cp++ = '\0';
164 ads->auth.realm = smb_xstrdup(cp);
165 strupper_m(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 = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
304 ads->auth.time_offset);
305 safe_free(upn);
306 if (ADS_ERR_OK(status)) {
307 d_printf("User %s added\n", argv[0]);
308 rc = 0;
309 goto done;
312 /* password didn't set, delete account */
313 d_printf("Could not add user %s. Error setting password %s\n",
314 argv[0], ads_errstr(status));
315 ads_msgfree(ads, res);
316 status=ads_find_user_acct(ads, &res, argv[0]);
317 if (ADS_ERR_OK(status)) {
318 userdn = ads_get_dn(ads, res);
319 ads_del_dn(ads, userdn);
320 ads_memfree(ads, userdn);
323 done:
324 if (res)
325 ads_msgfree(ads, res);
326 ads_destroy(&ads);
327 return rc;
330 static int ads_user_info(int argc, const char **argv)
332 ADS_STRUCT *ads;
333 ADS_STATUS rc;
334 void *res;
335 const char *attrs[] = {"memberOf", NULL};
336 char *searchstring=NULL;
337 char **grouplist;
338 char *escaped_user = escape_ldap_string_alloc(argv[0]);
340 if (argc < 1) return net_ads_user_usage(argc, argv);
342 if (!(ads = ads_startup())) return -1;
344 if (!escaped_user) {
345 d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
346 return -1;
349 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
350 rc = ads_search(ads, &res, searchstring, attrs);
351 safe_free(searchstring);
353 if (!ADS_ERR_OK(rc)) {
354 d_printf("ads_search: %s\n", ads_errstr(rc));
355 return -1;
358 grouplist = ldap_get_values(ads->ld, res, "memberOf");
360 if (grouplist) {
361 int i;
362 char **groupname;
363 for (i=0;grouplist[i];i++) {
364 groupname = ldap_explode_dn(grouplist[i], 1);
365 d_printf("%s\n", groupname[0]);
366 ldap_value_free(groupname);
368 ldap_value_free(grouplist);
371 ads_msgfree(ads, res);
373 ads_destroy(&ads);
374 return 0;
377 static int ads_user_delete(int argc, const char **argv)
379 ADS_STRUCT *ads;
380 ADS_STATUS rc;
381 void *res;
382 char *userdn;
384 if (argc < 1) return net_ads_user_usage(argc, argv);
386 if (!(ads = ads_startup())) return -1;
388 rc = ads_find_user_acct(ads, &res, argv[0]);
389 if (!ADS_ERR_OK(rc)) {
390 DEBUG(0, ("User %s does not exist\n", argv[0]));
391 return -1;
393 userdn = ads_get_dn(ads, res);
394 ads_msgfree(ads, res);
395 rc = ads_del_dn(ads, userdn);
396 ads_memfree(ads, userdn);
397 if (!ADS_ERR_OK(rc)) {
398 d_printf("User %s deleted\n", argv[0]);
399 return 0;
401 d_printf("Error deleting user %s: %s\n", argv[0],
402 ads_errstr(rc));
403 return -1;
406 int net_ads_user(int argc, const char **argv)
408 struct functable func[] = {
409 {"ADD", ads_user_add},
410 {"INFO", ads_user_info},
411 {"DELETE", ads_user_delete},
412 {NULL, NULL}
414 ADS_STRUCT *ads;
415 ADS_STATUS rc;
416 const char *shortattrs[] = {"sAMAccountName", NULL};
417 const char *longattrs[] = {"sAMAccountName", "description", NULL};
418 char *disp_fields[2] = {NULL, NULL};
420 if (argc == 0) {
421 if (!(ads = ads_startup())) return -1;
423 if (opt_long_list_entries)
424 d_printf("\nUser name Comment"\
425 "\n-----------------------------\n");
427 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
428 LDAP_SCOPE_SUBTREE,
429 "(objectclass=user)",
430 opt_long_list_entries ? longattrs :
431 shortattrs, usergrp_display,
432 disp_fields);
433 ads_destroy(&ads);
434 return 0;
437 return net_run_function(argc, argv, func, net_ads_user_usage);
440 static int net_ads_group_usage(int argc, const char **argv)
442 return net_help_group(argc, argv);
445 static int ads_group_add(int argc, const char **argv)
447 ADS_STRUCT *ads;
448 ADS_STATUS status;
449 void *res=NULL;
450 int rc = -1;
452 if (argc < 1) return net_ads_group_usage(argc, argv);
454 if (!(ads = ads_startup())) return -1;
456 status = ads_find_user_acct(ads, &res, argv[0]);
458 if (!ADS_ERR_OK(status)) {
459 d_printf("ads_group_add: %s\n", ads_errstr(status));
460 goto done;
463 if (ads_count_replies(ads, res)) {
464 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
465 ads_msgfree(ads, res);
466 goto done;
469 status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
471 if (ADS_ERR_OK(status)) {
472 d_printf("Group %s added\n", argv[0]);
473 rc = 0;
474 } else {
475 d_printf("Could not add group %s: %s\n", argv[0],
476 ads_errstr(status));
479 done:
480 if (res)
481 ads_msgfree(ads, res);
482 ads_destroy(&ads);
483 return rc;
486 static int ads_group_delete(int argc, const char **argv)
488 ADS_STRUCT *ads;
489 ADS_STATUS rc;
490 void *res;
491 char *groupdn;
493 if (argc < 1) return net_ads_group_usage(argc, argv);
495 if (!(ads = ads_startup())) return -1;
497 rc = ads_find_user_acct(ads, &res, argv[0]);
498 if (!ADS_ERR_OK(rc)) {
499 DEBUG(0, ("Group %s does not exist\n", argv[0]));
500 return -1;
502 groupdn = ads_get_dn(ads, res);
503 ads_msgfree(ads, res);
504 rc = ads_del_dn(ads, groupdn);
505 ads_memfree(ads, groupdn);
506 if (!ADS_ERR_OK(rc)) {
507 d_printf("Group %s deleted\n", argv[0]);
508 return 0;
510 d_printf("Error deleting group %s: %s\n", argv[0],
511 ads_errstr(rc));
512 return -1;
515 int net_ads_group(int argc, const char **argv)
517 struct functable func[] = {
518 {"ADD", ads_group_add},
519 {"DELETE", ads_group_delete},
520 {NULL, NULL}
522 ADS_STRUCT *ads;
523 ADS_STATUS rc;
524 const char *shortattrs[] = {"sAMAccountName", NULL};
525 const char *longattrs[] = {"sAMAccountName", "description", NULL};
526 char *disp_fields[2] = {NULL, NULL};
528 if (argc == 0) {
529 if (!(ads = ads_startup())) return -1;
531 if (opt_long_list_entries)
532 d_printf("\nGroup name Comment"\
533 "\n-----------------------------\n");
534 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
535 LDAP_SCOPE_SUBTREE,
536 "(objectclass=group)",
537 opt_long_list_entries ? longattrs :
538 shortattrs, usergrp_display,
539 disp_fields);
541 ads_destroy(&ads);
542 return 0;
544 return net_run_function(argc, argv, func, net_ads_group_usage);
547 static int net_ads_status(int argc, const char **argv)
549 ADS_STRUCT *ads;
550 ADS_STATUS rc;
551 void *res;
553 if (!(ads = ads_startup())) return -1;
555 rc = ads_find_machine_acct(ads, &res, global_myname());
556 if (!ADS_ERR_OK(rc)) {
557 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
558 return -1;
561 if (ads_count_replies(ads, res) == 0) {
562 d_printf("No machine account for '%s' found\n", global_myname());
563 return -1;
566 ads_dump(ads, res);
568 return 0;
571 static int net_ads_leave(int argc, const char **argv)
573 ADS_STRUCT *ads = NULL;
574 ADS_STATUS rc;
576 if (!secrets_init()) {
577 DEBUG(1,("Failed to initialise secrets database\n"));
578 return -1;
581 if (!opt_password) {
582 char *user_name;
583 asprintf(&user_name, "%s$", global_myname());
584 opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL);
585 opt_user_name = user_name;
588 if (!(ads = ads_startup())) {
589 return -1;
592 rc = ads_leave_realm(ads, global_myname());
593 if (!ADS_ERR_OK(rc)) {
594 d_printf("Failed to delete host '%s' from the '%s' realm.\n",
595 global_myname(), ads->config.realm);
596 return -1;
599 d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
601 return 0;
604 static int net_ads_join_ok(void)
606 char *user_name;
607 ADS_STRUCT *ads = NULL;
609 if (!secrets_init()) {
610 DEBUG(1,("Failed to initialise secrets database\n"));
611 return -1;
614 asprintf(&user_name, "%s$", global_myname());
615 opt_user_name = user_name;
616 opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL);
618 if (!(ads = ads_startup())) {
619 return -1;
622 ads_destroy(&ads);
623 return 0;
627 check that an existing join is OK
629 int net_ads_testjoin(int argc, const char **argv)
631 use_in_memory_ccache();
633 /* Display success or failure */
634 if (net_ads_join_ok() != 0) {
635 fprintf(stderr,"Join to domain is not valid\n");
636 return -1;
639 printf("Join is OK\n");
640 return 0;
644 join a domain using ADS
646 int net_ads_join(int argc, const char **argv)
648 ADS_STRUCT *ads;
649 ADS_STATUS rc;
650 char *password;
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;
660 if (argc > 0) org_unit = argv[0];
662 if (!secrets_init()) {
663 DEBUG(1,("Failed to initialise secrets database\n"));
664 return -1;
667 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
668 password = strdup(tmp_password);
670 if (!(ads = ads_startup())) return -1;
672 ou_str = ads_ou_string(org_unit);
673 asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
674 free(ou_str);
676 rc = ads_search_dn(ads, &res, dn, NULL);
677 ads_msgfree(ads, res);
679 if (rc.error_type == ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
680 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
681 org_unit, dn);
682 return -1;
684 free(dn);
686 if (!ADS_ERR_OK(rc)) {
687 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
688 return -1;
691 rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
692 if (!ADS_ERR_OK(rc)) {
693 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
694 return -1;
697 rc = ads_domain_sid(ads, &dom_sid);
698 if (!ADS_ERR_OK(rc)) {
699 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
700 return -1;
703 rc = ads_set_machine_password(ads, global_myname(), password);
704 if (!ADS_ERR_OK(rc)) {
705 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
706 return -1;
709 if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
710 DEBUG(1,("Failed to save domain sid\n"));
711 return -1;
714 if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
715 DEBUG(1,("Failed to save machine password\n"));
716 return -1;
719 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
721 free(password);
723 return 0;
726 int net_ads_printer_usage(int argc, const char **argv)
728 d_printf(
729 "\nnet ads printer search <printer>"
730 "\n\tsearch for a printer in the directory"
731 "\nnet ads printer info <printer> <server>"
732 "\n\tlookup info in directory for printer on server"
733 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
734 "\nnet ads printer publish <printername>"
735 "\n\tpublish printer in directory"
736 "\n\t(note: printer name is required)\n"
737 "\nnet ads printer remove <printername>"
738 "\n\tremove printer from directory"
739 "\n\t(note: printer name is required)\n");
740 return -1;
743 static int net_ads_printer_search(int argc, const char **argv)
745 ADS_STRUCT *ads;
746 ADS_STATUS rc;
747 void *res = NULL;
749 if (!(ads = ads_startup()))
750 return -1;
752 rc = ads_find_printers(ads, &res);
754 if (!ADS_ERR_OK(rc)) {
755 d_printf("ads_find_printer: %s\n", ads_errstr(rc));
756 ads_msgfree(ads, res);
757 return -1;
760 if (ads_count_replies(ads, res) == 0) {
761 d_printf("No results found\n");
762 ads_msgfree(ads, res);
763 return -1;
766 ads_dump(ads, res);
767 ads_msgfree(ads, res);
769 return 0;
772 static int net_ads_printer_info(int argc, const char **argv)
774 ADS_STRUCT *ads;
775 ADS_STATUS rc;
776 const char *servername, *printername;
777 void *res = NULL;
779 if (!(ads = ads_startup())) return -1;
781 if (argc > 0)
782 printername = argv[0];
783 else
784 printername = "*";
786 if (argc > 1)
787 servername = argv[1];
788 else
789 servername = global_myname();
791 rc = ads_find_printer_on_server(ads, &res, printername, servername);
793 if (!ADS_ERR_OK(rc)) {
794 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
795 ads_msgfree(ads, res);
796 return -1;
799 if (ads_count_replies(ads, res) == 0) {
800 d_printf("Printer '%s' not found\n", printername);
801 ads_msgfree(ads, res);
802 return -1;
805 ads_dump(ads, res);
806 ads_msgfree(ads, res);
808 return 0;
811 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
813 return;
816 static int net_ads_printer_publish(int argc, const char **argv)
818 ADS_STRUCT *ads;
819 ADS_STATUS rc;
820 const char *servername, *printername;
821 struct cli_state *cli;
822 struct in_addr server_ip;
823 NTSTATUS nt_status;
824 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
825 ADS_MODLIST mods = ads_init_mods(mem_ctx);
826 char *prt_dn, *srv_dn, **srv_cn;
827 void *res = NULL;
829 if (!(ads = ads_startup())) return -1;
831 if (argc < 1)
832 return net_ads_printer_usage(argc, argv);
834 printername = argv[0];
836 if (argc == 2)
837 servername = argv[1];
838 else
839 servername = global_myname();
841 /* Get printer data from SPOOLSS */
843 resolve_name(servername, &server_ip, 0x20);
845 nt_status = cli_full_connection(&cli, global_myname(), servername,
846 &server_ip, 0,
847 "IPC$", "IPC",
848 opt_user_name, opt_workgroup,
849 opt_password ? opt_password : "",
850 CLI_FULL_CONNECTION_USE_KERBEROS,
851 Undefined, NULL);
853 if (NT_STATUS_IS_ERR(nt_status)) {
854 d_printf("Unable to open a connnection to %s to obtain data "
855 "for %s\n", servername, printername);
856 return -1;
859 /* Publish on AD server */
861 ads_find_machine_acct(ads, &res, servername);
863 if (ads_count_replies(ads, res) == 0) {
864 d_printf("Could not find machine account for server %s\n",
865 servername);
866 return -1;
869 srv_dn = ldap_get_dn(ads->ld, res);
870 srv_cn = ldap_explode_dn(srv_dn, 1);
872 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
874 cli_nt_session_open(cli, PI_SPOOLSS);
875 get_remote_printer_publishing_data(cli, mem_ctx, &mods, printername);
877 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
878 if (!ADS_ERR_OK(rc)) {
879 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
880 return -1;
883 d_printf("published printer\n");
885 return 0;
888 static int net_ads_printer_remove(int argc, const char **argv)
890 ADS_STRUCT *ads;
891 ADS_STATUS rc;
892 const char *servername;
893 char *prt_dn;
894 void *res = NULL;
896 if (!(ads = ads_startup())) return -1;
898 if (argc < 1)
899 return net_ads_printer_usage(argc, argv);
901 if (argc > 1)
902 servername = argv[1];
903 else
904 servername = global_myname();
906 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
908 if (!ADS_ERR_OK(rc)) {
909 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
910 ads_msgfree(ads, res);
911 return -1;
914 if (ads_count_replies(ads, res) == 0) {
915 d_printf("Printer '%s' not found\n", argv[1]);
916 ads_msgfree(ads, res);
917 return -1;
920 prt_dn = ads_get_dn(ads, res);
921 ads_msgfree(ads, res);
922 rc = ads_del_dn(ads, prt_dn);
923 ads_memfree(ads, prt_dn);
925 if (!ADS_ERR_OK(rc)) {
926 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
927 return -1;
930 return 0;
933 static int net_ads_printer(int argc, const char **argv)
935 struct functable func[] = {
936 {"SEARCH", net_ads_printer_search},
937 {"INFO", net_ads_printer_info},
938 {"PUBLISH", net_ads_printer_publish},
939 {"REMOVE", net_ads_printer_remove},
940 {NULL, NULL}
943 return net_run_function(argc, argv, func, net_ads_printer_usage);
947 static int net_ads_password(int argc, const char **argv)
949 ADS_STRUCT *ads;
950 const char *auth_principal = opt_user_name;
951 const char *auth_password = opt_password;
952 char *realm = NULL;
953 char *new_password = NULL;
954 char *c, *prompt;
955 const char *user;
956 ADS_STATUS ret;
958 if (opt_user_name == NULL || opt_password == NULL) {
959 d_printf("You must supply an administrator username/password\n");
960 return -1;
964 if (argc != 1) {
965 d_printf("ERROR: You must say which username to change password for\n");
966 return -1;
969 user = argv[0];
970 if (!strchr(user, '@')) {
971 asprintf(&c, "%s@%s", argv[0], lp_realm());
972 user = c;
975 use_in_memory_ccache();
976 c = strchr(auth_principal, '@');
977 if (c) {
978 realm = ++c;
979 } else {
980 realm = lp_realm();
983 /* use the realm so we can eventually change passwords for users
984 in realms other than default */
985 if (!(ads = ads_init(realm, NULL, NULL))) return -1;
987 /* we don't actually need a full connect, but it's the easy way to
988 fill in the KDC's addresss */
989 ads_connect(ads);
991 if (!ads || !ads->config.realm) {
992 d_printf("Didn't find the kerberos server!\n");
993 return -1;
996 asprintf(&prompt, "Enter new password for %s:", user);
998 new_password = getpass(prompt);
1000 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1001 auth_password, user, new_password, ads->auth.time_offset);
1002 if (!ADS_ERR_OK(ret)) {
1003 d_printf("Password change failed :-( ...\n");
1004 ads_destroy(&ads);
1005 free(prompt);
1006 return -1;
1009 d_printf("Password change for %s completed.\n", user);
1010 ads_destroy(&ads);
1011 free(prompt);
1013 return 0;
1017 int net_ads_changetrustpw(int argc, const char **argv)
1019 ADS_STRUCT *ads;
1020 char *host_principal;
1021 char *hostname;
1022 ADS_STATUS ret;
1023 char *user_name;
1025 if (!secrets_init()) {
1026 DEBUG(1,("Failed to initialise secrets database\n"));
1027 return -1;
1030 asprintf(&user_name, "%s$", global_myname());
1031 opt_user_name = user_name;
1033 opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL);
1035 use_in_memory_ccache();
1037 if (!(ads = ads_startup())) {
1038 return -1;
1041 hostname = strdup(global_myname());
1042 strlower_m(hostname);
1043 asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
1044 SAFE_FREE(hostname);
1045 d_printf("Changing password for principal: HOST/%s\n", host_principal);
1047 ret = ads_change_trust_account_password(ads, host_principal);
1049 if (!ADS_ERR_OK(ret)) {
1050 d_printf("Password change failed :-( ...\n");
1051 ads_destroy(&ads);
1052 SAFE_FREE(host_principal);
1053 return -1;
1056 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
1057 ads_destroy(&ads);
1058 SAFE_FREE(host_principal);
1060 return 0;
1064 help for net ads search
1066 static int net_ads_search_usage(int argc, const char **argv)
1068 d_printf(
1069 "\nnet ads search <expression> <attributes...>\n"\
1070 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1071 "The expression is a standard LDAP search expression, and the\n"\
1072 "attributes are a list of LDAP fields to show in the results\n\n"\
1073 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1075 net_common_flags_usage(argc, argv);
1076 return -1;
1081 general ADS search function. Useful in diagnosing problems in ADS
1083 static int net_ads_search(int argc, const char **argv)
1085 ADS_STRUCT *ads;
1086 ADS_STATUS rc;
1087 const char *ldap_exp;
1088 const char **attrs;
1089 void *res = NULL;
1091 if (argc < 1) {
1092 return net_ads_search_usage(argc, argv);
1095 if (!(ads = ads_startup())) {
1096 return -1;
1099 ldap_exp = argv[0];
1100 attrs = (argv + 1);
1102 rc = ads_do_search_all(ads, ads->config.bind_path,
1103 LDAP_SCOPE_SUBTREE,
1104 ldap_exp, attrs, &res);
1105 if (!ADS_ERR_OK(rc)) {
1106 d_printf("search failed: %s\n", ads_errstr(rc));
1107 return -1;
1110 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1112 /* dump the results */
1113 ads_dump(ads, res);
1115 ads_msgfree(ads, res);
1116 ads_destroy(&ads);
1118 return 0;
1123 help for net ads search
1125 static int net_ads_dn_usage(int argc, const char **argv)
1127 d_printf(
1128 "\nnet ads dn <dn> <attributes...>\n"\
1129 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1130 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1131 "to show in the results\n\n"\
1132 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1134 net_common_flags_usage(argc, argv);
1135 return -1;
1140 general ADS search function. Useful in diagnosing problems in ADS
1142 static int net_ads_dn(int argc, const char **argv)
1144 ADS_STRUCT *ads;
1145 ADS_STATUS rc;
1146 const char *dn;
1147 const char **attrs;
1148 void *res = NULL;
1150 if (argc < 1) {
1151 return net_ads_dn_usage(argc, argv);
1154 if (!(ads = ads_startup())) {
1155 return -1;
1158 dn = argv[0];
1159 attrs = (argv + 1);
1161 rc = ads_do_search_all(ads, dn,
1162 LDAP_SCOPE_BASE,
1163 "(objectclass=*)", attrs, &res);
1164 if (!ADS_ERR_OK(rc)) {
1165 d_printf("search failed: %s\n", ads_errstr(rc));
1166 return -1;
1169 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1171 /* dump the results */
1172 ads_dump(ads, res);
1174 ads_msgfree(ads, res);
1175 ads_destroy(&ads);
1177 return 0;
1181 int net_ads_help(int argc, const char **argv)
1183 struct functable func[] = {
1184 {"USER", net_ads_user_usage},
1185 {"GROUP", net_ads_group_usage},
1186 {"PRINTER", net_ads_printer_usage},
1187 {"SEARCH", net_ads_search_usage},
1188 #if 0
1189 {"INFO", net_ads_info},
1190 {"JOIN", net_ads_join},
1191 {"LEAVE", net_ads_leave},
1192 {"STATUS", net_ads_status},
1193 {"PASSWORD", net_ads_password},
1194 {"CHANGETRUSTPW", net_ads_changetrustpw},
1195 #endif
1196 {NULL, NULL}
1199 return net_run_function(argc, argv, func, net_ads_usage);
1202 int net_ads(int argc, const char **argv)
1204 struct functable func[] = {
1205 {"INFO", net_ads_info},
1206 {"JOIN", net_ads_join},
1207 {"TESTJOIN", net_ads_testjoin},
1208 {"LEAVE", net_ads_leave},
1209 {"STATUS", net_ads_status},
1210 {"USER", net_ads_user},
1211 {"GROUP", net_ads_group},
1212 {"PASSWORD", net_ads_password},
1213 {"CHANGETRUSTPW", net_ads_changetrustpw},
1214 {"PRINTER", net_ads_printer},
1215 {"SEARCH", net_ads_search},
1216 {"DN", net_ads_dn},
1217 {"WORKGROUP", net_ads_workgroup},
1218 {"LOOKUP", net_ads_lookup},
1219 {"HELP", net_ads_help},
1220 {NULL, NULL}
1223 return net_run_function(argc, argv, func, net_ads_usage);
1226 #else
1228 static int net_ads_noads(void)
1230 d_printf("ADS support not compiled in\n");
1231 return -1;
1234 int net_ads_usage(int argc, const char **argv)
1236 return net_ads_noads();
1239 int net_ads_help(int argc, const char **argv)
1241 return net_ads_noads();
1244 int net_ads_changetrustpw(int argc, const char **argv)
1246 return net_ads_noads();
1249 int net_ads_join(int argc, const char **argv)
1251 return net_ads_noads();
1254 int net_ads_user(int argc, const char **argv)
1256 return net_ads_noads();
1259 int net_ads_group(int argc, const char **argv)
1261 return net_ads_noads();
1264 /* this one shouldn't display a message */
1265 int net_ads_check(void)
1267 return -1;
1270 int net_ads(int argc, const char **argv)
1272 return net_ads_usage(argc, argv);
1275 #endif