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\tlist, add, or delete users in the realm\n"\
38 "\n\tlist, add, or delete groups in the realm\n"\
40 "\n\tshows some info on the server\n"\
42 "\n\tdump the machine account details to stdout\n"
43 "\nnet ads password <username@realm> -Uadmin_username@realm%%admin_pass"\
44 "\n\tchange a user's password using an admin account"\
45 "\n\t(note: use realm in UPPERCASE)\n"\
46 "\nnet ads chostpass"\
47 "\n\tchange the trust account password of this machine in the AD tree\n"\
48 "\nnet ads printer [info | publish | remove] <printername> <servername>"\
49 "\n\t lookup, add, or remove directory entry for a printer\n"\
51 "\n\tperform a raw LDAP search and dump the results\n"
57 static int net_ads_info(int argc, const char **argv)
61 ads = ads_init(NULL, NULL, opt_host, NULL, NULL);
65 d_printf("Didn't find the ldap server!\n");
69 d_printf("LDAP server: %s\n", ads->ldap_server);
70 d_printf("LDAP server name: %s\n", ads->ldap_server_name);
71 d_printf("Realm: %s\n", ads->realm);
72 d_printf("Bind Path: %s\n", ads->bind_path);
73 d_printf("LDAP port: %d\n", ads->ldap_port);
79 static ADS_STRUCT *ads_startup(void)
83 BOOL need_password = False;
84 BOOL second_time = False;
86 ads = ads_init(NULL, NULL, opt_host, NULL, NULL);
89 opt_user_name = "administrator";
92 if (opt_user_specified)
96 if (!opt_password && need_password) {
98 asprintf(&prompt,"%s password: ", opt_user_name);
99 opt_password = getpass(prompt);
104 ads->password = strdup(opt_password);
106 ads->user_name = strdup(opt_user_name);
108 status = ads_connect(ads);
109 if (!ADS_ERR_OK(status)) {
110 if (!need_password && !second_time) {
111 need_password = True;
115 DEBUG(1,("ads_connect: %s\n", ads_errstr(status)));
124 Check to see if connection can be made via ads.
125 ads_startup() stores the password in opt_password if it needs to so
126 that rpc or rap can use it without re-prompting.
128 int net_ads_check(void)
140 static BOOL usergrp_display(char *field, void **values, void *data_area)
142 char **disp_fields = (char **) data_area;
144 if (!field) { /* must be end of record */
145 if (!strchr_m(disp_fields[0], '$')) {
147 d_printf("%-21.21s %-50.50s\n",
148 disp_fields[0], disp_fields[1]);
150 d_printf("%s\n", disp_fields[0]);
152 SAFE_FREE(disp_fields[0]);
153 SAFE_FREE(disp_fields[1]);
156 if (!values) /* must be new field, indicate string field */
158 if (StrCaseCmp(field, "sAMAccountName") == 0) {
159 disp_fields[0] = strdup((char *) values[0]);
161 if (StrCaseCmp(field, "description") == 0)
162 disp_fields[1] = strdup((char *) values[0]);
163 return True; /* always strings here */
166 static int net_ads_user_usage(int argc, const char **argv)
168 return net_help_user(argc, argv);
171 static int ads_user_add(int argc, const char **argv)
179 if (argc < 1) return net_ads_user_usage(argc, argv);
181 if (!(ads = ads_startup())) return -1;
183 status = ads_find_user_acct(ads, &res, argv[0]);
185 if (!ADS_ERR_OK(status)) {
186 d_printf("ads_user_add: %s\n", ads_errstr(status));
190 if (ads_count_replies(ads, res)) {
191 d_printf("ads_user_add: User %s already exists\n", argv[0]);
195 status = ads_add_user_acct(ads, argv[0], opt_comment);
197 if (!ADS_ERR_OK(status)) {
198 d_printf("Could not add user %s: %s\n", argv[0],
203 /* if no password is to be set, we're done */
205 d_printf("User %s added\n", argv[0]);
210 /* try setting the password */
211 asprintf(&upn, "%s@%s", argv[0], ads->realm);
212 status = krb5_set_password(ads->kdc_server, upn, argv[1]);
214 if (ADS_ERR_OK(status)) {
215 d_printf("User %s added\n", argv[0]);
220 /* password didn't set, delete account */
221 d_printf("Could not add user %s. Error setting password %s\n",
222 argv[0], ads_errstr(status));
223 ads_msgfree(ads, res);
224 status=ads_find_user_acct(ads, &res, argv[0]);
225 if (ADS_ERR_OK(status)) {
226 userdn = ads_get_dn(ads, res);
227 ads_del_dn(ads, userdn);
228 ads_memfree(ads, userdn);
233 ads_msgfree(ads, res);
238 static int ads_user_info(int argc, const char **argv)
243 const char *attrs[] = {"memberOf", NULL};
244 char *searchstring=NULL;
247 if (argc < 1) return net_ads_user_usage(argc, argv);
249 if (!(ads = ads_startup())) return -1;
251 asprintf(&searchstring, "(sAMAccountName=%s)", argv[0]);
252 rc = ads_search(ads, &res, searchstring, attrs);
253 safe_free(searchstring);
255 if (!ADS_ERR_OK(rc)) {
256 d_printf("ads_search: %s\n", ads_errstr(rc));
260 grouplist = ldap_get_values(ads->ld, res, "memberOf");
265 for (i=0;grouplist[i];i++) {
266 groupname = ldap_explode_dn(grouplist[i], 1);
267 d_printf("%s\n", groupname[0]);
268 ldap_value_free(groupname);
270 ldap_value_free(grouplist);
273 ads_msgfree(ads, res);
279 static int ads_user_delete(int argc, const char **argv)
286 if (argc < 1) return net_ads_user_usage(argc, argv);
288 if (!(ads = ads_startup())) return -1;
290 rc = ads_find_user_acct(ads, &res, argv[0]);
291 if (!ADS_ERR_OK(rc)) {
292 DEBUG(0, ("User %s does not exist\n", argv[0]));
295 userdn = ads_get_dn(ads, res);
296 ads_msgfree(ads, res);
297 rc = ads_del_dn(ads, userdn);
298 ads_memfree(ads, userdn);
299 if (!ADS_ERR_OK(rc)) {
300 d_printf("User %s deleted\n", argv[0]);
303 d_printf("Error deleting user %s: %s\n", argv[0],
308 int net_ads_user(int argc, const char **argv)
310 struct functable func[] = {
311 {"ADD", ads_user_add},
312 {"INFO", ads_user_info},
313 {"DELETE", ads_user_delete},
318 const char *shortattrs[] = {"sAMAccountName", NULL};
319 const char *longattrs[] = {"sAMAccountName", "description", NULL};
320 char *disp_fields[2] = {NULL, NULL};
323 if (!(ads = ads_startup())) return -1;
325 if (opt_long_list_entries)
326 d_printf("\nUser name Comment"\
327 "\n-----------------------------\n");
329 rc = ads_do_search_all_fn(ads, ads->bind_path,
331 "(objectclass=user)",
332 opt_long_list_entries ? longattrs :
333 shortattrs, usergrp_display,
339 return net_run_function(argc, argv, func, net_ads_user_usage);
342 static int net_ads_group_usage(int argc, const char **argv)
344 return net_help_group(argc, argv);
347 static int ads_group_add(int argc, const char **argv)
354 if (argc < 1) return net_ads_group_usage(argc, argv);
356 if (!(ads = ads_startup())) return -1;
358 status = ads_find_user_acct(ads, &res, argv[0]);
360 if (!ADS_ERR_OK(status)) {
361 d_printf("ads_group_add: %s\n", ads_errstr(status));
365 if (ads_count_replies(ads, res)) {
366 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
367 ads_msgfree(ads, res);
371 status = ads_add_group_acct(ads, argv[0], opt_comment);
373 if (ADS_ERR_OK(status)) {
374 d_printf("Group %s added\n", argv[0]);
377 d_printf("Could not add group %s: %s\n", argv[0],
383 ads_msgfree(ads, res);
388 static int ads_group_delete(int argc, const char **argv)
395 if (argc < 1) return net_ads_group_usage(argc, argv);
397 if (!(ads = ads_startup())) return -1;
399 rc = ads_find_user_acct(ads, &res, argv[0]);
400 if (!ADS_ERR_OK(rc)) {
401 DEBUG(0, ("Group %s does not exist\n", argv[0]));
404 groupdn = ads_get_dn(ads, res);
405 ads_msgfree(ads, res);
406 rc = ads_del_dn(ads, groupdn);
407 ads_memfree(ads, groupdn);
408 if (!ADS_ERR_OK(rc)) {
409 d_printf("Group %s deleted\n", argv[0]);
412 d_printf("Error deleting group %s: %s\n", argv[0],
417 int net_ads_group(int argc, const char **argv)
419 struct functable func[] = {
420 {"ADD", ads_group_add},
421 {"DELETE", ads_group_delete},
426 const char *shortattrs[] = {"sAMAccountName", NULL};
427 const char *longattrs[] = {"sAMAccountName", "description", NULL};
428 char *disp_fields[2] = {NULL, NULL};
431 if (!(ads = ads_startup())) return -1;
433 if (opt_long_list_entries)
434 d_printf("\nGroup name Comment"\
435 "\n-----------------------------\n");
436 rc = ads_do_search_all_fn(ads, ads->bind_path,
438 "(objectclass=group)",
439 opt_long_list_entries ? longattrs :
440 shortattrs, usergrp_display,
446 return net_run_function(argc, argv, func, net_ads_group_usage);
449 static int net_ads_status(int argc, const char **argv)
453 extern pstring global_myname;
456 if (!(ads = ads_startup())) return -1;
458 rc = ads_find_machine_acct(ads, &res, global_myname);
459 if (!ADS_ERR_OK(rc)) {
460 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
464 if (ads_count_replies(ads, res) == 0) {
465 d_printf("No machine account for '%s' found\n", global_myname);
474 static int net_ads_leave(int argc, const char **argv)
476 ADS_STRUCT *ads = NULL;
478 extern pstring global_myname;
480 if (!secrets_init()) {
481 DEBUG(1,("Failed to initialise secrets database\n"));
486 asprintf(&opt_user_name, "%s$", global_myname);
487 opt_password = secrets_fetch_machine_password();
490 if (!(ads = ads_startup())) {
494 rc = ads_leave_realm(ads, global_myname);
495 if (!ADS_ERR_OK(rc)) {
496 d_printf("Failed to delete host '%s' from the '%s' realm.\n",
497 global_myname, ads->realm);
501 d_printf("Removed '%s' from realm '%s'\n", global_myname, ads->realm);
506 int net_ads_join(int argc, const char **argv)
512 extern pstring global_myname;
513 const char *org_unit = "Computers";
519 if (argc > 0) org_unit = argv[0];
521 if (!secrets_init()) {
522 DEBUG(1,("Failed to initialise secrets database\n"));
526 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
527 password = strdup(tmp_password);
529 if (!(ads = ads_startup())) return -1;
531 ou_str = ads_ou_string(org_unit);
532 asprintf(&dn, "%s,%s", ou_str, ads->bind_path);
535 rc = ads_search_dn(ads, &res, dn, NULL);
536 ads_msgfree(ads, res);
538 if (rc.error_type == ADS_ERROR_LDAP && rc.rc == LDAP_NO_SUCH_OBJECT) {
539 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
545 if (!ADS_ERR_OK(rc)) {
546 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
550 rc = ads_join_realm(ads, global_myname, org_unit);
551 if (!ADS_ERR_OK(rc)) {
552 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
556 rc = ads_set_machine_password(ads, global_myname, password);
557 if (!ADS_ERR_OK(rc)) {
558 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
562 rc = ads_domain_sid(ads, &dom_sid);
563 if (!ADS_ERR_OK(rc)) {
564 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
568 if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
569 DEBUG(1,("Failed to save domain sid\n"));
573 if (!secrets_store_machine_password(password)) {
574 DEBUG(1,("Failed to save machine password\n"));
578 d_printf("Joined '%s' to realm '%s'\n", global_myname, ads->realm);
585 int net_ads_printer_usage(int argc, const char **argv)
588 "\nnet ads printer info <printer> <server>"
589 "\n\tlookup info in directory for printer on server"
590 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
591 "\nnet ads printer publish <printername>"
592 "\n\tpublish printer in directory"
593 "\n\t(note: printer name is required)\n"
594 "\nnet ads printer remove <printername>"
595 "\n\tremove printer from directory"
596 "\n\t(note: printer name is required)\n");
600 static int net_ads_printer_info(int argc, const char **argv)
604 const char *servername, *printername;
605 extern pstring global_myname;
608 if (!(ads = ads_startup())) return -1;
611 printername = argv[0];
616 servername = argv[1];
618 servername = global_myname;
620 rc = ads_find_printer_on_server(ads, &res, printername, servername);
622 if (!ADS_ERR_OK(rc)) {
623 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
624 ads_msgfree(ads, res);
628 if (ads_count_replies(ads, res) == 0) {
629 d_printf("Printer '%s' not found\n", printername);
630 ads_msgfree(ads, res);
635 ads_msgfree(ads, res);
640 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
645 static int net_ads_printer_publish(int argc, const char **argv)
649 char *uncname, *servername;
650 ADS_PRINTER_ENTRY prt;
651 extern pstring global_myname;
652 char *ports[2] = {"Samba", NULL};
655 these const strings are only here as an example. The attributes
656 they represent are not implemented yet
658 const char *bins[] = {"Tray 21", NULL};
659 const char *media[] = {"Letter", NULL};
660 const char *orients[] = {"PORTRAIT", NULL};
662 if (!(ads = ads_startup())) return -1;
665 return net_ads_printer_usage(argc, argv);
667 memset(&prt, 0, sizeof(ADS_PRINTER_ENTRY));
669 /* we don't sue the servername or unc name provided by
670 get_a_printer, because the server name might be
671 localhost or an ip address */
672 prt.printerName = argv[0];
673 asprintf(&servername, "%s.%s", global_myname, ads->realm);
674 prt.serverName = servername;
675 prt.shortServerName = global_myname;
676 prt.versionNumber = "4";
677 asprintf(&uncname, "\\\\%s\\%s", global_myname, argv[0]);
679 prt.printBinNames = (char **) bins;
680 prt.printMediaSupported = (char **) media;
681 prt.printOrientationsSupported = (char **) orients;
682 prt.portName = (char **) ports;
683 prt.printSpooling = "PrintAfterSpooled";
685 rc = ads_add_printer(ads, &prt);
686 if (!ADS_ERR_OK(rc)) {
687 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
691 d_printf("published printer\n");
696 static int net_ads_printer_remove(int argc, const char **argv)
700 char *servername, *prt_dn;
701 extern pstring global_myname;
704 if (!(ads = ads_startup())) return -1;
707 return net_ads_printer_usage(argc, argv);
710 servername = argv[1];
712 servername = global_myname;
714 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
716 if (!ADS_ERR_OK(rc)) {
717 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
718 ads_msgfree(ads, res);
722 if (ads_count_replies(ads, res) == 0) {
723 d_printf("Printer '%s' not found\n", argv[1]);
724 ads_msgfree(ads, res);
728 prt_dn = ads_get_dn(ads, res);
729 ads_msgfree(ads, res);
730 rc = ads_del_dn(ads, prt_dn);
731 ads_memfree(ads, prt_dn);
733 if (!ADS_ERR_OK(rc)) {
734 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
741 static int net_ads_printer(int argc, const char **argv)
743 struct functable func[] = {
744 {"INFO", net_ads_printer_info},
745 {"PUBLISH", net_ads_printer_publish},
746 {"REMOVE", net_ads_printer_remove},
750 return net_run_function(argc, argv, func, net_ads_printer_usage);
754 static int net_ads_password(int argc, const char **argv)
757 char *auth_principal = opt_user_name;
758 char *auth_password = opt_password;
760 char *new_password = NULL;
766 if ((argc != 1) || (opt_user_name == NULL) ||
767 (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
768 (strchr(argv[0], '@') == NULL)) {
769 return net_ads_usage(argc, argv);
772 c = strchr(auth_principal, '@');
775 /* use the realm so we can eventually change passwords for users
776 in realms other than default */
777 if (!(ads = ads_init(realm, NULL, NULL, NULL, NULL))) return -1;
779 asprintf(&prompt, "Enter new password for %s:", argv[0]);
781 new_password = getpass(prompt);
783 ret = kerberos_set_password(ads->kdc_server, auth_principal,
784 auth_password, argv[0], new_password);
785 if (!ADS_ERR_OK(ret)) {
786 d_printf("Password change failed :-( ...\n");
792 d_printf("Password change for %s completed.\n", argv[0]);
800 static int net_ads_change_localhost_pass(int argc, const char **argv)
803 extern pstring global_myname;
804 char *host_principal;
808 if (!(ads = ads_init_simple())) return -1;
810 hostname = strdup(global_myname);
812 asprintf(&host_principal, "%s@%s", hostname, ads->realm);
814 d_printf("Changing password for principal: HOST/%s\n", host_principal);
816 ret = ads_change_trust_account_password(ads, host_principal);
818 if (!ADS_ERR_OK(ret)) {
819 d_printf("Password change failed :-( ...\n");
821 SAFE_FREE(host_principal);
825 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
827 SAFE_FREE(host_principal);
833 help for net ads search
835 static int net_ads_search_usage(int argc, const char **argv)
838 "\nnet ads search <expression> <attributes...>\n"\
839 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
840 "The expression is a standard LDAP search expression, and the\n"\
841 "attributes are a list of LDAP fields to show in the results\n\n"\
842 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
844 net_common_flags_usage(argc, argv);
850 general ADS search function. Useful in diagnosing problems in ADS
852 static int net_ads_search(int argc, const char **argv)
861 return net_ads_search_usage(argc, argv);
864 if (!(ads = ads_startup())) {
871 rc = ads_do_search_all(ads, ads->bind_path,
874 if (!ADS_ERR_OK(rc)) {
875 d_printf("search failed: %s\n", ads_errstr(rc));
879 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
881 /* dump the results */
884 ads_msgfree(ads, res);
891 int net_ads_help(int argc, const char **argv)
893 struct functable func[] = {
894 {"USER", net_ads_user_usage},
895 {"GROUP", net_ads_group_usage},
896 {"PRINTER", net_ads_printer_usage},
897 {"SEARCH", net_ads_search_usage},
899 {"INFO", net_ads_info},
900 {"JOIN", net_ads_join},
901 {"LEAVE", net_ads_leave},
902 {"STATUS", net_ads_status},
903 {"PASSWORD", net_ads_password},
904 {"CHOSTPASS", net_ads_change_localhost_pass},
909 return net_run_function(argc, argv, func, net_ads_usage);
912 int net_ads(int argc, const char **argv)
914 struct functable func[] = {
915 {"INFO", net_ads_info},
916 {"JOIN", net_ads_join},
917 {"LEAVE", net_ads_leave},
918 {"STATUS", net_ads_status},
919 {"USER", net_ads_user},
920 {"GROUP", net_ads_group},
921 {"PASSWORD", net_ads_password},
922 {"CHOSTPASS", net_ads_change_localhost_pass},
923 {"PRINTER", net_ads_printer},
924 {"SEARCH", net_ads_search},
925 {"HELP", net_ads_help},
929 return net_run_function(argc, argv, func, net_ads_usage);
934 static int net_ads_noads(void)
936 d_printf("ADS support not compiled in\n");
940 int net_ads_usage(int argc, const char **argv)
942 return net_ads_noads();
945 int net_ads_help(int argc, const char **argv)
947 return net_ads_noads();
950 int net_ads_join(int argc, const char **argv)
952 return net_ads_noads();
955 int net_ads_user(int argc, const char **argv)
957 return net_ads_noads();
960 int net_ads_group(int argc, const char **argv)
962 return net_ads_noads();
965 /* this one shouldn't display a message */
966 int net_ads_check(void)
971 int net_ads(int argc, const char **argv)
973 return net_ads_usage(argc, argv);