2 Samba Unix/Linux SMB client library
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.
24 #include "../utils/net.h"
28 int net_ads_usage(int argc, const char **argv)
31 "\nnet ads join <org_unit>"\
32 "\n\tjoins the local machine to a ADS realm\n"\
34 "\n\tremoves the local machine from a ADS realm\n"\
36 "\n\ttests that an exiting join is OK\n"\
38 "\n\tlist, add, or delete users in the realm\n"\
40 "\n\tlist, add, or delete groups in the realm\n"\
42 "\n\tshows some info on the server\n"\
44 "\n\tdump the machine account details to stdout\n"
45 "\nnet ads password <username@realm> -Uadmin_username@realm%%admin_pass"\
46 "\n\tchange a user's password using an admin account"\
47 "\n\t(note: use realm in UPPERCASE)\n"\
48 "\nnet ads chostpass"\
49 "\n\tchange the trust account password of this machine in the AD tree\n"\
50 "\nnet ads printer [info | publish | remove] <printername> <servername>"\
51 "\n\t lookup, add, or remove directory entry for a printer\n"\
53 "\n\tperform a raw LDAP search and dump the results\n"
60 this implements the CLDAP based netlogon lookup requests
61 for finding the domain controller of a ADS domain
63 static int net_ads_lookup(int argc, const char **argv)
67 ads = ads_init(NULL, NULL, opt_host);
69 ads->auth.flags |= ADS_AUTH_NO_BIND;
74 if (!ads || !ads->config.realm) {
75 d_printf("Didn't find the cldap server!\n");
79 return ads_cldap_netlogon(ads);
84 static int net_ads_info(int argc, const char **argv)
88 ads = ads_init(NULL, NULL, opt_host);
91 ads->auth.flags |= ADS_AUTH_NO_BIND;
96 if (!ads || !ads->config.realm) {
97 d_printf("Didn't find the ldap server!\n");
101 d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
102 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
103 d_printf("Realm: %s\n", ads->config.realm);
104 d_printf("Bind Path: %s\n", ads->config.bind_path);
105 d_printf("LDAP port: %d\n", ads->ldap_port);
106 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
112 static ADS_STRUCT *ads_startup(void)
116 BOOL need_password = False;
117 BOOL second_time = False;
119 ads = ads_init(NULL, NULL, opt_host);
121 if (!opt_user_name) {
122 opt_user_name = "administrator";
125 if (opt_user_specified)
126 need_password = True;
129 if (!opt_password && need_password) {
131 asprintf(&prompt,"%s password: ", opt_user_name);
132 opt_password = getpass(prompt);
137 ads->auth.password = strdup(opt_password);
139 ads->auth.user_name = strdup(opt_user_name);
141 status = ads_connect(ads);
142 if (!ADS_ERR_OK(status)) {
143 if (!need_password && !second_time) {
144 need_password = True;
148 DEBUG(1,("ads_connect: %s\n", ads_errstr(status)));
157 Check to see if connection can be made via ads.
158 ads_startup() stores the password in opt_password if it needs to so
159 that rpc or rap can use it without re-prompting.
161 int net_ads_check(void)
173 determine the netbios workgroup name for a domain
175 static int net_ads_workgroup(int argc, const char **argv)
181 if (!(ads = ads_startup())) return -1;
183 if (!(ctx = talloc_init("net_ads_workgroup"))) {
187 if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
188 d_printf("Failed to find workgroup for realm '%s'\n",
194 d_printf("Workgroup: %s\n", workgroup);
203 static BOOL usergrp_display(char *field, void **values, void *data_area)
205 char **disp_fields = (char **) data_area;
207 if (!field) { /* must be end of record */
208 if (!strchr_m(disp_fields[0], '$')) {
210 d_printf("%-21.21s %-50.50s\n",
211 disp_fields[0], disp_fields[1]);
213 d_printf("%s\n", disp_fields[0]);
215 SAFE_FREE(disp_fields[0]);
216 SAFE_FREE(disp_fields[1]);
219 if (!values) /* must be new field, indicate string field */
221 if (StrCaseCmp(field, "sAMAccountName") == 0) {
222 disp_fields[0] = strdup((char *) values[0]);
224 if (StrCaseCmp(field, "description") == 0)
225 disp_fields[1] = strdup((char *) values[0]);
229 static int net_ads_user_usage(int argc, const char **argv)
231 return net_help_user(argc, argv);
234 static int ads_user_add(int argc, const char **argv)
242 if (argc < 1) return net_ads_user_usage(argc, argv);
244 if (!(ads = ads_startup())) return -1;
246 status = ads_find_user_acct(ads, &res, argv[0]);
248 if (!ADS_ERR_OK(status)) {
249 d_printf("ads_user_add: %s\n", ads_errstr(status));
253 if (ads_count_replies(ads, res)) {
254 d_printf("ads_user_add: User %s already exists\n", argv[0]);
258 status = ads_add_user_acct(ads, argv[0], opt_comment);
260 if (!ADS_ERR_OK(status)) {
261 d_printf("Could not add user %s: %s\n", argv[0],
266 /* if no password is to be set, we're done */
268 d_printf("User %s added\n", argv[0]);
273 /* try setting the password */
274 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
275 status = krb5_set_password(ads->auth.kdc_server, upn, argv[1], ads->auth.time_offset);
277 if (ADS_ERR_OK(status)) {
278 d_printf("User %s added\n", argv[0]);
283 /* password didn't set, delete account */
284 d_printf("Could not add user %s. Error setting password %s\n",
285 argv[0], ads_errstr(status));
286 ads_msgfree(ads, res);
287 status=ads_find_user_acct(ads, &res, argv[0]);
288 if (ADS_ERR_OK(status)) {
289 userdn = ads_get_dn(ads, res);
290 ads_del_dn(ads, userdn);
291 ads_memfree(ads, userdn);
296 ads_msgfree(ads, res);
301 static int ads_user_info(int argc, const char **argv)
306 const char *attrs[] = {"memberOf", NULL};
307 char *searchstring=NULL;
310 if (argc < 1) return net_ads_user_usage(argc, argv);
312 if (!(ads = ads_startup())) return -1;
314 asprintf(&searchstring, "(sAMAccountName=%s)", argv[0]);
315 rc = ads_search(ads, &res, searchstring, attrs);
316 safe_free(searchstring);
318 if (!ADS_ERR_OK(rc)) {
319 d_printf("ads_search: %s\n", ads_errstr(rc));
323 grouplist = ldap_get_values(ads->ld, res, "memberOf");
328 for (i=0;grouplist[i];i++) {
329 groupname = ldap_explode_dn(grouplist[i], 1);
330 d_printf("%s\n", groupname[0]);
331 ldap_value_free(groupname);
333 ldap_value_free(grouplist);
336 ads_msgfree(ads, res);
342 static int ads_user_delete(int argc, const char **argv)
349 if (argc < 1) return net_ads_user_usage(argc, argv);
351 if (!(ads = ads_startup())) return -1;
353 rc = ads_find_user_acct(ads, &res, argv[0]);
354 if (!ADS_ERR_OK(rc)) {
355 DEBUG(0, ("User %s does not exist\n", argv[0]));
358 userdn = ads_get_dn(ads, res);
359 ads_msgfree(ads, res);
360 rc = ads_del_dn(ads, userdn);
361 ads_memfree(ads, userdn);
362 if (!ADS_ERR_OK(rc)) {
363 d_printf("User %s deleted\n", argv[0]);
366 d_printf("Error deleting user %s: %s\n", argv[0],
371 int net_ads_user(int argc, const char **argv)
373 struct functable func[] = {
374 {"ADD", ads_user_add},
375 {"INFO", ads_user_info},
376 {"DELETE", ads_user_delete},
381 const char *shortattrs[] = {"sAMAccountName", NULL};
382 const char *longattrs[] = {"sAMAccountName", "description", NULL};
383 char *disp_fields[2] = {NULL, NULL};
386 if (!(ads = ads_startup())) return -1;
388 if (opt_long_list_entries)
389 d_printf("\nUser name Comment"\
390 "\n-----------------------------\n");
392 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
394 "(objectclass=user)",
395 opt_long_list_entries ? longattrs :
396 shortattrs, usergrp_display,
402 return net_run_function(argc, argv, func, net_ads_user_usage);
405 static int net_ads_group_usage(int argc, const char **argv)
407 return net_help_group(argc, argv);
410 static int ads_group_add(int argc, const char **argv)
417 if (argc < 1) return net_ads_group_usage(argc, argv);
419 if (!(ads = ads_startup())) return -1;
421 status = ads_find_user_acct(ads, &res, argv[0]);
423 if (!ADS_ERR_OK(status)) {
424 d_printf("ads_group_add: %s\n", ads_errstr(status));
428 if (ads_count_replies(ads, res)) {
429 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
430 ads_msgfree(ads, res);
434 status = ads_add_group_acct(ads, argv[0], opt_comment);
436 if (ADS_ERR_OK(status)) {
437 d_printf("Group %s added\n", argv[0]);
440 d_printf("Could not add group %s: %s\n", argv[0],
446 ads_msgfree(ads, res);
451 static int ads_group_delete(int argc, const char **argv)
458 if (argc < 1) return net_ads_group_usage(argc, argv);
460 if (!(ads = ads_startup())) return -1;
462 rc = ads_find_user_acct(ads, &res, argv[0]);
463 if (!ADS_ERR_OK(rc)) {
464 DEBUG(0, ("Group %s does not exist\n", argv[0]));
467 groupdn = ads_get_dn(ads, res);
468 ads_msgfree(ads, res);
469 rc = ads_del_dn(ads, groupdn);
470 ads_memfree(ads, groupdn);
471 if (!ADS_ERR_OK(rc)) {
472 d_printf("Group %s deleted\n", argv[0]);
475 d_printf("Error deleting group %s: %s\n", argv[0],
480 int net_ads_group(int argc, const char **argv)
482 struct functable func[] = {
483 {"ADD", ads_group_add},
484 {"DELETE", ads_group_delete},
489 const char *shortattrs[] = {"sAMAccountName", NULL};
490 const char *longattrs[] = {"sAMAccountName", "description", NULL};
491 char *disp_fields[2] = {NULL, NULL};
494 if (!(ads = ads_startup())) return -1;
496 if (opt_long_list_entries)
497 d_printf("\nGroup name Comment"\
498 "\n-----------------------------\n");
499 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
501 "(objectclass=group)",
502 opt_long_list_entries ? longattrs :
503 shortattrs, usergrp_display,
509 return net_run_function(argc, argv, func, net_ads_group_usage);
512 static int net_ads_status(int argc, const char **argv)
518 if (!(ads = ads_startup())) return -1;
520 rc = ads_find_machine_acct(ads, &res, global_myname());
521 if (!ADS_ERR_OK(rc)) {
522 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
526 if (ads_count_replies(ads, res) == 0) {
527 d_printf("No machine account for '%s' found\n", global_myname());
536 static int net_ads_leave(int argc, const char **argv)
538 ADS_STRUCT *ads = NULL;
541 if (!secrets_init()) {
542 DEBUG(1,("Failed to initialise secrets database\n"));
547 asprintf(&opt_user_name, "%s$", global_myname());
548 opt_password = secrets_fetch_machine_password();
551 if (!(ads = ads_startup())) {
555 rc = ads_leave_realm(ads, global_myname());
556 if (!ADS_ERR_OK(rc)) {
557 d_printf("Failed to delete host '%s' from the '%s' realm.\n",
558 global_myname(), ads->config.realm);
562 d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
567 static int net_ads_join_ok(void)
569 ADS_STRUCT *ads = NULL;
571 if (!secrets_init()) {
572 DEBUG(1,("Failed to initialise secrets database\n"));
576 asprintf(&opt_user_name, "%s$", global_myname());
577 opt_password = secrets_fetch_machine_password();
579 if (!(ads = ads_startup())) {
588 check that an existing join is OK
590 int net_ads_testjoin(int argc, const char **argv)
592 /* Display success or failure */
593 if (net_ads_join_ok() != 0) {
594 fprintf(stderr,"Join to domain is not valid\n");
598 printf("Join is OK\n");
603 join a domain using ADS
605 int net_ads_join(int argc, const char **argv)
611 const char *org_unit = "Computers";
617 if (argc > 0) org_unit = argv[0];
619 if (!secrets_init()) {
620 DEBUG(1,("Failed to initialise secrets database\n"));
624 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
625 password = strdup(tmp_password);
627 if (!(ads = ads_startup())) return -1;
629 ou_str = ads_ou_string(org_unit);
630 asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
633 rc = ads_search_dn(ads, &res, dn, NULL);
634 ads_msgfree(ads, res);
636 if (rc.error_type == ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
637 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
643 if (!ADS_ERR_OK(rc)) {
644 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
648 rc = ads_join_realm(ads, global_myname(), org_unit);
649 if (!ADS_ERR_OK(rc)) {
650 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
654 rc = ads_domain_sid(ads, &dom_sid);
655 if (!ADS_ERR_OK(rc)) {
656 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
660 rc = ads_set_machine_password(ads, global_myname(), password);
661 if (!ADS_ERR_OK(rc)) {
662 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
666 if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
667 DEBUG(1,("Failed to save domain sid\n"));
671 if (!secrets_store_machine_password(password)) {
672 DEBUG(1,("Failed to save machine password\n"));
676 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
683 int net_ads_printer_usage(int argc, const char **argv)
686 "\nnet ads printer info <printer> <server>"
687 "\n\tlookup info in directory for printer on server"
688 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
689 "\nnet ads printer publish <printername>"
690 "\n\tpublish printer in directory"
691 "\n\t(note: printer name is required)\n"
692 "\nnet ads printer remove <printername>"
693 "\n\tremove printer from directory"
694 "\n\t(note: printer name is required)\n");
698 static int net_ads_printer_info(int argc, const char **argv)
702 const char *servername, *printername;
705 if (!(ads = ads_startup())) return -1;
708 printername = argv[0];
713 servername = argv[1];
715 servername = global_myname();
717 rc = ads_find_printer_on_server(ads, &res, printername, servername);
719 if (!ADS_ERR_OK(rc)) {
720 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
721 ads_msgfree(ads, res);
725 if (ads_count_replies(ads, res) == 0) {
726 d_printf("Printer '%s' not found\n", printername);
727 ads_msgfree(ads, res);
732 ads_msgfree(ads, res);
737 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
742 static int net_ads_printer_publish(int argc, const char **argv)
747 struct cli_state *cli;
748 struct in_addr server_ip;
750 extern char *opt_workgroup;
751 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
752 ADS_MODLIST mods = ads_init_mods(mem_ctx);
753 char *prt_dn, *srv_dn, **srv_cn;
756 if (!(ads = ads_startup())) return -1;
759 return net_ads_printer_usage(argc, argv);
762 servername = argv[1];
764 servername = global_myname();
766 ads_find_machine_acct(ads, &res, servername);
767 srv_dn = ldap_get_dn(ads->ld, res);
768 srv_cn = ldap_explode_dn(srv_dn, 1);
769 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], argv[0], srv_dn);
771 resolve_name(servername, &server_ip, 0x20);
773 nt_status = cli_full_connection(&cli, global_myname(), servername,
776 opt_user_name, opt_workgroup,
777 opt_password ? opt_password : "",
778 CLI_FULL_CONNECTION_USE_KERBEROS,
781 cli_nt_session_open(cli, PI_SPOOLSS);
782 get_remote_printer_publishing_data(cli, mem_ctx, &mods, argv[0]);
784 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
785 if (!ADS_ERR_OK(rc)) {
786 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
790 d_printf("published printer\n");
795 static int net_ads_printer_remove(int argc, const char **argv)
799 const char *servername;
803 if (!(ads = ads_startup())) return -1;
806 return net_ads_printer_usage(argc, argv);
809 servername = argv[1];
811 servername = global_myname();
813 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
815 if (!ADS_ERR_OK(rc)) {
816 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
817 ads_msgfree(ads, res);
821 if (ads_count_replies(ads, res) == 0) {
822 d_printf("Printer '%s' not found\n", argv[1]);
823 ads_msgfree(ads, res);
827 prt_dn = ads_get_dn(ads, res);
828 ads_msgfree(ads, res);
829 rc = ads_del_dn(ads, prt_dn);
830 ads_memfree(ads, prt_dn);
832 if (!ADS_ERR_OK(rc)) {
833 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
840 static int net_ads_printer(int argc, const char **argv)
842 struct functable func[] = {
843 {"INFO", net_ads_printer_info},
844 {"PUBLISH", net_ads_printer_publish},
845 {"REMOVE", net_ads_printer_remove},
849 return net_run_function(argc, argv, func, net_ads_printer_usage);
853 static int net_ads_password(int argc, const char **argv)
856 char *auth_principal = opt_user_name;
857 char *auth_password = opt_password;
859 char *new_password = NULL;
865 if ((argc != 1) || (opt_user_name == NULL) ||
866 (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
867 (strchr(argv[0], '@') == NULL)) {
868 return net_ads_usage(argc, argv);
871 c = strchr(auth_principal, '@');
874 /* use the realm so we can eventually change passwords for users
875 in realms other than default */
876 if (!(ads = ads_init(realm, NULL, NULL))) return -1;
878 asprintf(&prompt, "Enter new password for %s:", argv[0]);
880 new_password = getpass(prompt);
882 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
883 auth_password, argv[0], new_password, ads->auth.time_offset);
884 if (!ADS_ERR_OK(ret)) {
885 d_printf("Password change failed :-( ...\n");
891 d_printf("Password change for %s completed.\n", argv[0]);
899 static int net_ads_change_localhost_pass(int argc, const char **argv)
902 char *host_principal;
906 if (!secrets_init()) {
907 DEBUG(1,("Failed to initialise secrets database\n"));
911 asprintf(&opt_user_name, "%s$", global_myname());
912 opt_password = secrets_fetch_machine_password();
914 if (!(ads = ads_startup())) {
918 hostname = strdup(global_myname());
920 asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
922 d_printf("Changing password for principal: HOST/%s\n", host_principal);
924 ret = ads_change_trust_account_password(ads, host_principal);
926 if (!ADS_ERR_OK(ret)) {
927 d_printf("Password change failed :-( ...\n");
929 SAFE_FREE(host_principal);
933 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
935 SAFE_FREE(host_principal);
941 help for net ads search
943 static int net_ads_search_usage(int argc, const char **argv)
946 "\nnet ads search <expression> <attributes...>\n"\
947 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
948 "The expression is a standard LDAP search expression, and the\n"\
949 "attributes are a list of LDAP fields to show in the results\n\n"\
950 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
952 net_common_flags_usage(argc, argv);
958 general ADS search function. Useful in diagnosing problems in ADS
960 static int net_ads_search(int argc, const char **argv)
969 return net_ads_search_usage(argc, argv);
972 if (!(ads = ads_startup())) {
979 rc = ads_do_search_all(ads, ads->config.bind_path,
982 if (!ADS_ERR_OK(rc)) {
983 d_printf("search failed: %s\n", ads_errstr(rc));
987 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
989 /* dump the results */
992 ads_msgfree(ads, res);
999 int net_ads_help(int argc, const char **argv)
1001 struct functable func[] = {
1002 {"USER", net_ads_user_usage},
1003 {"GROUP", net_ads_group_usage},
1004 {"PRINTER", net_ads_printer_usage},
1005 {"SEARCH", net_ads_search_usage},
1007 {"INFO", net_ads_info},
1008 {"JOIN", net_ads_join},
1009 {"LEAVE", net_ads_leave},
1010 {"STATUS", net_ads_status},
1011 {"PASSWORD", net_ads_password},
1012 {"CHOSTPASS", net_ads_change_localhost_pass},
1017 return net_run_function(argc, argv, func, net_ads_usage);
1020 int net_ads(int argc, const char **argv)
1022 struct functable func[] = {
1023 {"INFO", net_ads_info},
1024 {"JOIN", net_ads_join},
1025 {"TESTJOIN", net_ads_testjoin},
1026 {"LEAVE", net_ads_leave},
1027 {"STATUS", net_ads_status},
1028 {"USER", net_ads_user},
1029 {"GROUP", net_ads_group},
1030 {"PASSWORD", net_ads_password},
1031 {"CHOSTPASS", net_ads_change_localhost_pass},
1032 {"PRINTER", net_ads_printer},
1033 {"SEARCH", net_ads_search},
1034 {"WORKGROUP", net_ads_workgroup},
1035 {"LOOKUP", net_ads_lookup},
1036 {"HELP", net_ads_help},
1040 return net_run_function(argc, argv, func, net_ads_usage);
1045 static int net_ads_noads(void)
1047 d_printf("ADS support not compiled in\n");
1051 int net_ads_usage(int argc, const char **argv)
1053 return net_ads_noads();
1056 int net_ads_help(int argc, const char **argv)
1058 return net_ads_noads();
1061 int net_ads_join(int argc, const char **argv)
1063 return net_ads_noads();
1066 int net_ads_user(int argc, const char **argv)
1068 return net_ads_noads();
1071 int net_ads_group(int argc, const char **argv)
1073 return net_ads_noads();
1076 /* this one shouldn't display a message */
1077 int net_ads_check(void)
1082 int net_ads(int argc, const char **argv)
1084 return net_ads_usage(argc, argv);