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_named("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)
746 char *uncname, *servername;
747 ADS_PRINTER_ENTRY prt;
748 char *ports[2] = {"Samba", NULL};
751 these const strings are only here as an example. The attributes
752 they represent are not implemented yet
754 const char *bins[] = {"Tray 21", NULL};
755 const char *media[] = {"Letter", NULL};
756 const char *orients[] = {"PORTRAIT", NULL};
758 if (!(ads = ads_startup())) return -1;
761 return net_ads_printer_usage(argc, argv);
763 memset(&prt, 0, sizeof(ADS_PRINTER_ENTRY));
765 /* we don't sue the servername or unc name provided by
766 get_a_printer, because the server name might be
767 localhost or an ip address */
768 prt.printerName = argv[0];
769 asprintf(&servername, "%s.%s", global_myname(), ads->config.realm);
770 prt.serverName = servername;
771 prt.shortServerName = global_myname();
772 prt.versionNumber = "4";
773 asprintf(&uncname, "\\\\%s\\%s", global_myname(), argv[0]);
775 prt.printBinNames = (char **) bins;
776 prt.printMediaSupported = (char **) media;
777 prt.printOrientationsSupported = (char **) orients;
778 prt.portName = (char **) ports;
779 prt.printSpooling = "PrintAfterSpooled";
781 rc = ads_add_printer(ads, &prt);
782 if (!ADS_ERR_OK(rc)) {
783 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
787 d_printf("published printer\n");
792 static int net_ads_printer_remove(int argc, const char **argv)
796 const char *servername;
800 if (!(ads = ads_startup())) return -1;
803 return net_ads_printer_usage(argc, argv);
806 servername = argv[1];
808 servername = global_myname();
810 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
812 if (!ADS_ERR_OK(rc)) {
813 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
814 ads_msgfree(ads, res);
818 if (ads_count_replies(ads, res) == 0) {
819 d_printf("Printer '%s' not found\n", argv[1]);
820 ads_msgfree(ads, res);
824 prt_dn = ads_get_dn(ads, res);
825 ads_msgfree(ads, res);
826 rc = ads_del_dn(ads, prt_dn);
827 ads_memfree(ads, prt_dn);
829 if (!ADS_ERR_OK(rc)) {
830 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
837 static int net_ads_printer(int argc, const char **argv)
839 struct functable func[] = {
840 {"INFO", net_ads_printer_info},
841 {"PUBLISH", net_ads_printer_publish},
842 {"REMOVE", net_ads_printer_remove},
846 return net_run_function(argc, argv, func, net_ads_printer_usage);
850 static int net_ads_password(int argc, const char **argv)
853 char *auth_principal = opt_user_name;
854 char *auth_password = opt_password;
856 char *new_password = NULL;
862 if ((argc != 1) || (opt_user_name == NULL) ||
863 (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
864 (strchr(argv[0], '@') == NULL)) {
865 return net_ads_usage(argc, argv);
868 c = strchr(auth_principal, '@');
871 /* use the realm so we can eventually change passwords for users
872 in realms other than default */
873 if (!(ads = ads_init(realm, NULL, NULL))) return -1;
875 asprintf(&prompt, "Enter new password for %s:", argv[0]);
877 new_password = getpass(prompt);
879 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
880 auth_password, argv[0], new_password, ads->auth.time_offset);
881 if (!ADS_ERR_OK(ret)) {
882 d_printf("Password change failed :-( ...\n");
888 d_printf("Password change for %s completed.\n", argv[0]);
896 static int net_ads_change_localhost_pass(int argc, const char **argv)
899 char *host_principal;
903 if (!secrets_init()) {
904 DEBUG(1,("Failed to initialise secrets database\n"));
908 asprintf(&opt_user_name, "%s$", global_myname());
909 opt_password = secrets_fetch_machine_password();
911 if (!(ads = ads_startup())) {
915 hostname = strdup(global_myname());
917 asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
919 d_printf("Changing password for principal: HOST/%s\n", host_principal);
921 ret = ads_change_trust_account_password(ads, host_principal);
923 if (!ADS_ERR_OK(ret)) {
924 d_printf("Password change failed :-( ...\n");
926 SAFE_FREE(host_principal);
930 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
932 SAFE_FREE(host_principal);
938 help for net ads search
940 static int net_ads_search_usage(int argc, const char **argv)
943 "\nnet ads search <expression> <attributes...>\n"\
944 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
945 "The expression is a standard LDAP search expression, and the\n"\
946 "attributes are a list of LDAP fields to show in the results\n\n"\
947 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
949 net_common_flags_usage(argc, argv);
955 general ADS search function. Useful in diagnosing problems in ADS
957 static int net_ads_search(int argc, const char **argv)
966 return net_ads_search_usage(argc, argv);
969 if (!(ads = ads_startup())) {
976 rc = ads_do_search_all(ads, ads->config.bind_path,
979 if (!ADS_ERR_OK(rc)) {
980 d_printf("search failed: %s\n", ads_errstr(rc));
984 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
986 /* dump the results */
989 ads_msgfree(ads, res);
996 int net_ads_help(int argc, const char **argv)
998 struct functable func[] = {
999 {"USER", net_ads_user_usage},
1000 {"GROUP", net_ads_group_usage},
1001 {"PRINTER", net_ads_printer_usage},
1002 {"SEARCH", net_ads_search_usage},
1004 {"INFO", net_ads_info},
1005 {"JOIN", net_ads_join},
1006 {"LEAVE", net_ads_leave},
1007 {"STATUS", net_ads_status},
1008 {"PASSWORD", net_ads_password},
1009 {"CHOSTPASS", net_ads_change_localhost_pass},
1014 return net_run_function(argc, argv, func, net_ads_usage);
1017 int net_ads(int argc, const char **argv)
1019 struct functable func[] = {
1020 {"INFO", net_ads_info},
1021 {"JOIN", net_ads_join},
1022 {"TESTJOIN", net_ads_testjoin},
1023 {"LEAVE", net_ads_leave},
1024 {"STATUS", net_ads_status},
1025 {"USER", net_ads_user},
1026 {"GROUP", net_ads_group},
1027 {"PASSWORD", net_ads_password},
1028 {"CHOSTPASS", net_ads_change_localhost_pass},
1029 {"PRINTER", net_ads_printer},
1030 {"SEARCH", net_ads_search},
1031 {"WORKGROUP", net_ads_workgroup},
1032 {"LOOKUP", net_ads_lookup},
1033 {"HELP", net_ads_help},
1037 return net_run_function(argc, argv, func, net_ads_usage);
1042 static int net_ads_noads(void)
1044 d_printf("ADS support not compiled in\n");
1048 int net_ads_usage(int argc, const char **argv)
1050 return net_ads_noads();
1053 int net_ads_help(int argc, const char **argv)
1055 return net_ads_noads();
1058 int net_ads_join(int argc, const char **argv)
1060 return net_ads_noads();
1063 int net_ads_user(int argc, const char **argv)
1065 return net_ads_noads();
1068 int net_ads_group(int argc, const char **argv)
1070 return net_ads_noads();
1073 /* this one shouldn't display a message */
1074 int net_ads_check(void)
1079 int net_ads(int argc, const char **argv)
1081 return net_ads_usage(argc, argv);