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"
46 "\n\tperform a CLDAP search on the server\n"
47 "\nnet ads password <username@realm> <password> -Uadmin_username@realm%%admin_pass"\
48 "\n\tchange a user's password using an admin account"\
49 "\n\t(note: use realm in UPPERCASE, prompts if password is obmitted)\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"\
55 "\n\tperform a raw LDAP search and dump the results\n"
57 "\n\tperform a raw LDAP search and dump attributes of a particular DN\n"
59 "\n\tcreates and updates the kerberos system keytab file\n"
66 this implements the CLDAP based netlogon lookup requests
67 for finding the domain controller of a ADS domain
69 static int net_ads_lookup(int argc, const char **argv)
73 ads = ads_init(NULL, opt_target_workgroup, opt_host);
75 ads->auth.flags |= ADS_AUTH_NO_BIND;
81 d_printf("Didn't find the cldap server!\n");
83 } if (!ads->config.realm) {
84 ads->config.realm = opt_target_workgroup;
88 return ads_cldap_netlogon(ads);
93 static int net_ads_info(int argc, const char **argv)
97 ads = ads_init(NULL, opt_target_workgroup, opt_host);
100 ads->auth.flags |= ADS_AUTH_NO_BIND;
105 if (!ads || !ads->config.realm) {
106 d_printf("Didn't find the ldap server!\n");
110 d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
111 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
112 d_printf("Realm: %s\n", ads->config.realm);
113 d_printf("Bind Path: %s\n", ads->config.bind_path);
114 d_printf("LDAP port: %d\n", ads->ldap_port);
115 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
117 d_printf("KDC server: %s\n", ads->auth.kdc_server );
118 d_printf("Server time offset: %d\n", ads->auth.time_offset );
123 static void use_in_memory_ccache(void) {
124 /* Use in-memory credentials cache so we do not interfere with
125 * existing credentials */
126 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
129 static ADS_STRUCT *ads_startup(void)
133 BOOL need_password = False;
134 BOOL second_time = False;
137 /* lp_realm() should be handled by a command line param,
138 However, the join requires that realm be set in smb.conf
139 and compares our realm with the remote server's so this is
140 ok until someone needs more flexibility */
142 ads = ads_init(lp_realm(), opt_target_workgroup, opt_host);
144 if (!opt_user_name) {
145 opt_user_name = "administrator";
148 if (opt_user_specified) {
149 need_password = True;
153 if (!opt_password && need_password && !opt_machine_pass) {
155 asprintf(&prompt,"%s's password: ", opt_user_name);
156 opt_password = getpass(prompt);
161 use_in_memory_ccache();
162 ads->auth.password = smb_xstrdup(opt_password);
165 ads->auth.user_name = smb_xstrdup(opt_user_name);
168 * If the username is of the form "name@realm",
169 * extract the realm and convert to upper case.
170 * This is only used to establish the connection.
172 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
174 ads->auth.realm = smb_xstrdup(cp);
175 strupper_m(ads->auth.realm);
178 status = ads_connect(ads);
180 if (!ADS_ERR_OK(status)) {
181 if (!need_password && !second_time) {
182 need_password = True;
186 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
195 Check to see if connection can be made via ads.
196 ads_startup() stores the password in opt_password if it needs to so
197 that rpc or rap can use it without re-prompting.
199 int net_ads_check(void)
211 determine the netbios workgroup name for a domain
213 static int net_ads_workgroup(int argc, const char **argv)
217 const char *workgroup;
219 if (!(ads = ads_startup())) return -1;
221 if (!(ctx = talloc_init("net_ads_workgroup"))) {
226 if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
227 d_printf("Failed to find workgroup for realm '%s'\n",
234 d_printf("Workgroup: %s\n", workgroup);
243 static BOOL usergrp_display(char *field, void **values, void *data_area)
245 char **disp_fields = (char **) data_area;
247 if (!field) { /* must be end of record */
248 if (!strchr_m(disp_fields[0], '$')) {
250 d_printf("%-21.21s %s\n",
251 disp_fields[0], disp_fields[1]);
253 d_printf("%s\n", disp_fields[0]);
255 SAFE_FREE(disp_fields[0]);
256 SAFE_FREE(disp_fields[1]);
259 if (!values) /* must be new field, indicate string field */
261 if (StrCaseCmp(field, "sAMAccountName") == 0) {
262 disp_fields[0] = SMB_STRDUP((char *) values[0]);
264 if (StrCaseCmp(field, "description") == 0)
265 disp_fields[1] = SMB_STRDUP((char *) values[0]);
269 static int net_ads_user_usage(int argc, const char **argv)
271 return net_help_user(argc, argv);
274 static int ads_user_add(int argc, const char **argv)
282 if (argc < 1) return net_ads_user_usage(argc, argv);
284 if (!(ads = ads_startup())) {
288 status = ads_find_user_acct(ads, &res, argv[0]);
290 if (!ADS_ERR_OK(status)) {
291 d_printf("ads_user_add: %s\n", ads_errstr(status));
295 if (ads_count_replies(ads, res)) {
296 d_printf("ads_user_add: User %s already exists\n", argv[0]);
300 if (opt_container == NULL) {
301 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
304 status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
306 if (!ADS_ERR_OK(status)) {
307 d_printf("Could not add user %s: %s\n", argv[0],
312 /* if no password is to be set, we're done */
314 d_printf("User %s added\n", argv[0]);
319 /* try setting the password */
320 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
321 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
322 ads->auth.time_offset);
324 if (ADS_ERR_OK(status)) {
325 d_printf("User %s added\n", argv[0]);
330 /* password didn't set, delete account */
331 d_printf("Could not add user %s. Error setting password %s\n",
332 argv[0], ads_errstr(status));
333 ads_msgfree(ads, res);
334 status=ads_find_user_acct(ads, &res, argv[0]);
335 if (ADS_ERR_OK(status)) {
336 userdn = ads_get_dn(ads, res);
337 ads_del_dn(ads, userdn);
338 ads_memfree(ads, userdn);
343 ads_msgfree(ads, res);
348 static int ads_user_info(int argc, const char **argv)
353 const char *attrs[] = {"memberOf", NULL};
354 char *searchstring=NULL;
356 char *escaped_user = escape_ldap_string_alloc(argv[0]);
359 return net_ads_user_usage(argc, argv);
362 if (!(ads = ads_startup())) {
367 d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
372 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
373 rc = ads_search(ads, &res, searchstring, attrs);
374 safe_free(searchstring);
376 if (!ADS_ERR_OK(rc)) {
377 d_printf("ads_search: %s\n", ads_errstr(rc));
382 grouplist = ldap_get_values(ads->ld, res, "memberOf");
387 for (i=0;grouplist[i];i++) {
388 groupname = ldap_explode_dn(grouplist[i], 1);
389 d_printf("%s\n", groupname[0]);
390 ldap_value_free(groupname);
392 ldap_value_free(grouplist);
395 ads_msgfree(ads, res);
400 static int ads_user_delete(int argc, const char **argv)
408 return net_ads_user_usage(argc, argv);
411 if (!(ads = ads_startup())) {
415 rc = ads_find_user_acct(ads, &res, argv[0]);
416 if (!ADS_ERR_OK(rc)) {
417 DEBUG(0, ("User %s does not exist\n", argv[0]));
421 userdn = ads_get_dn(ads, res);
422 ads_msgfree(ads, res);
423 rc = ads_del_dn(ads, userdn);
424 ads_memfree(ads, userdn);
425 if (!ADS_ERR_OK(rc)) {
426 d_printf("User %s deleted\n", argv[0]);
430 d_printf("Error deleting user %s: %s\n", argv[0],
436 int net_ads_user(int argc, const char **argv)
438 struct functable func[] = {
439 {"ADD", ads_user_add},
440 {"INFO", ads_user_info},
441 {"DELETE", ads_user_delete},
446 const char *shortattrs[] = {"sAMAccountName", NULL};
447 const char *longattrs[] = {"sAMAccountName", "description", NULL};
448 char *disp_fields[2] = {NULL, NULL};
451 if (!(ads = ads_startup())) {
455 if (opt_long_list_entries)
456 d_printf("\nUser name Comment"\
457 "\n-----------------------------\n");
459 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
461 "(objectclass=user)",
462 opt_long_list_entries ? longattrs :
463 shortattrs, usergrp_display,
469 return net_run_function(argc, argv, func, net_ads_user_usage);
472 static int net_ads_group_usage(int argc, const char **argv)
474 return net_help_group(argc, argv);
477 static int ads_group_add(int argc, const char **argv)
485 return net_ads_group_usage(argc, argv);
488 if (!(ads = ads_startup())) {
492 status = ads_find_user_acct(ads, &res, argv[0]);
494 if (!ADS_ERR_OK(status)) {
495 d_printf("ads_group_add: %s\n", ads_errstr(status));
499 if (ads_count_replies(ads, res)) {
500 d_printf("ads_group_add: Group %s already exists\n", argv[0]);
501 ads_msgfree(ads, res);
505 if (opt_container == NULL) {
506 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
509 status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
511 if (ADS_ERR_OK(status)) {
512 d_printf("Group %s added\n", argv[0]);
515 d_printf("Could not add group %s: %s\n", argv[0],
521 ads_msgfree(ads, res);
526 static int ads_group_delete(int argc, const char **argv)
534 return net_ads_group_usage(argc, argv);
537 if (!(ads = ads_startup())) {
541 rc = ads_find_user_acct(ads, &res, argv[0]);
542 if (!ADS_ERR_OK(rc)) {
543 DEBUG(0, ("Group %s does not exist\n", argv[0]));
547 groupdn = ads_get_dn(ads, res);
548 ads_msgfree(ads, res);
549 rc = ads_del_dn(ads, groupdn);
550 ads_memfree(ads, groupdn);
551 if (!ADS_ERR_OK(rc)) {
552 d_printf("Group %s deleted\n", argv[0]);
556 d_printf("Error deleting group %s: %s\n", argv[0],
562 int net_ads_group(int argc, const char **argv)
564 struct functable func[] = {
565 {"ADD", ads_group_add},
566 {"DELETE", ads_group_delete},
571 const char *shortattrs[] = {"sAMAccountName", NULL};
572 const char *longattrs[] = {"sAMAccountName", "description", NULL};
573 char *disp_fields[2] = {NULL, NULL};
576 if (!(ads = ads_startup())) {
580 if (opt_long_list_entries)
581 d_printf("\nGroup name Comment"\
582 "\n-----------------------------\n");
583 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
585 "(objectclass=group)",
586 opt_long_list_entries ? longattrs :
587 shortattrs, usergrp_display,
593 return net_run_function(argc, argv, func, net_ads_group_usage);
596 static int net_ads_status(int argc, const char **argv)
602 if (!(ads = ads_startup())) {
606 rc = ads_find_machine_acct(ads, &res, global_myname());
607 if (!ADS_ERR_OK(rc)) {
608 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
613 if (ads_count_replies(ads, res) == 0) {
614 d_printf("No machine account for '%s' found\n", global_myname());
624 static int net_ads_leave(int argc, const char **argv)
626 ADS_STRUCT *ads = NULL;
629 if (!secrets_init()) {
630 DEBUG(1,("Failed to initialise secrets database\n"));
635 net_use_machine_password();
638 if (!(ads = ads_startup())) {
642 rc = ads_leave_realm(ads, global_myname());
643 if (!ADS_ERR_OK(rc)) {
644 d_printf("Failed to delete host '%s' from the '%s' realm.\n",
645 global_myname(), ads->config.realm);
650 d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
655 static int net_ads_join_ok(void)
657 ADS_STRUCT *ads = NULL;
659 if (!secrets_init()) {
660 DEBUG(1,("Failed to initialise secrets database\n"));
664 net_use_machine_password();
666 if (!(ads = ads_startup())) {
675 check that an existing join is OK
677 int net_ads_testjoin(int argc, const char **argv)
679 use_in_memory_ccache();
681 /* Display success or failure */
682 if (net_ads_join_ok() != 0) {
683 fprintf(stderr,"Join to domain is not valid\n");
687 printf("Join is OK\n");
692 join a domain using ADS
694 int net_ads_join(int argc, const char **argv)
699 char *machine_account = NULL;
701 const char *org_unit = NULL;
706 uint32 sec_channel_type = SEC_CHAN_WKSTA;
707 uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT;
708 const char *short_domain_name = NULL;
709 TALLOC_CTX *ctx = NULL;
715 if (!secrets_init()) {
716 DEBUG(1,("Failed to initialise secrets database\n"));
720 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
721 password = SMB_STRDUP(tmp_password);
723 if (!(ads = ads_startup())) {
728 d_printf("realm must be set in in smb.conf for ADS join to succeed.\n");
733 if (strcmp(ads->config.realm, lp_realm()) != 0) {
734 d_printf("realm of remote server (%s) and realm in smb.conf (%s) DO NOT match. Aborting join\n", ads->config.realm, lp_realm());
739 ou_str = ads_ou_string(ads,org_unit);
740 asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
743 rc = ads_search_dn(ads, &res, dn, NULL);
744 ads_msgfree(ads, res);
746 if (rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
747 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
754 if (!ADS_ERR_OK(rc)) {
755 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
760 rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
761 if (!ADS_ERR_OK(rc)) {
762 d_printf("ads_join_realm: %s\n", ads_errstr(rc));
767 rc = ads_domain_sid(ads, &dom_sid);
768 if (!ADS_ERR_OK(rc)) {
769 d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
774 if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
775 d_printf("asprintf failed\n");
780 rc = ads_set_machine_password(ads, machine_account, password);
781 if (!ADS_ERR_OK(rc)) {
782 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
787 /* make sure we get the right workgroup */
789 if ( !(ctx = talloc_init("net ads join")) ) {
790 d_printf("talloc_init() failed!\n");
795 rc = ads_workgroup_name(ads, ctx, &short_domain_name);
796 if ( ADS_ERR_OK(rc) ) {
797 if ( !strequal(lp_workgroup(), short_domain_name) ) {
798 d_printf("The workgroup in smb.conf does not match the short\n");
799 d_printf("domain name obtained from the server.\n");
800 d_printf("Using the name [%s] from the server.\n", short_domain_name);
801 d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
804 short_domain_name = lp_workgroup();
807 d_printf("Using short domain name -- %s\n", short_domain_name);
809 /* HACK ALRET! Store the sid and password under bother the lp_workgroup()
810 value from smb.conf and the string returned from the server. The former is
811 neede to bootstrap winbindd's first connection to the DC to get the real
812 short domain name --jerry */
814 if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
815 DEBUG(1,("Failed to save domain sid\n"));
820 if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
821 DEBUG(1,("Failed to save machine password\n"));
827 if (!kerberos_derive_salting_principal(machine_account)) {
828 DEBUG(1,("Failed to determine salting principal\n"));
833 if (!kerberos_derive_cifs_salting_principals()) {
834 DEBUG(1,("Failed to determine salting principals\n"));
840 if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) {
841 DEBUG(1,("Failed to save domain sid\n"));
846 if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) {
847 DEBUG(1,("Failed to save machine password\n"));
852 /* Now build the keytab, using the same ADS connection */
853 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
854 DEBUG(1,("Error creating host keytab!\n"));
857 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
860 SAFE_FREE(machine_account);
868 int net_ads_printer_usage(int argc, const char **argv)
871 "\nnet ads printer search <printer>"
872 "\n\tsearch for a printer in the directory\n"
873 "\nnet ads printer info <printer> <server>"
874 "\n\tlookup info in directory for printer on server"
875 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
876 "\nnet ads printer publish <printername>"
877 "\n\tpublish printer in directory"
878 "\n\t(note: printer name is required)\n"
879 "\nnet ads printer remove <printername>"
880 "\n\tremove printer from directory"
881 "\n\t(note: printer name is required)\n");
885 static int net_ads_printer_search(int argc, const char **argv)
891 if (!(ads = ads_startup())) {
895 rc = ads_find_printers(ads, &res);
897 if (!ADS_ERR_OK(rc)) {
898 d_printf("ads_find_printer: %s\n", ads_errstr(rc));
899 ads_msgfree(ads, res);
904 if (ads_count_replies(ads, res) == 0) {
905 d_printf("No results found\n");
906 ads_msgfree(ads, res);
912 ads_msgfree(ads, res);
917 static int net_ads_printer_info(int argc, const char **argv)
921 const char *servername, *printername;
924 if (!(ads = ads_startup())) {
929 printername = argv[0];
935 servername = argv[1];
937 servername = global_myname();
940 rc = ads_find_printer_on_server(ads, &res, printername, servername);
942 if (!ADS_ERR_OK(rc)) {
943 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
944 ads_msgfree(ads, res);
949 if (ads_count_replies(ads, res) == 0) {
950 d_printf("Printer '%s' not found\n", printername);
951 ads_msgfree(ads, res);
957 ads_msgfree(ads, res);
963 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
968 static int net_ads_printer_publish(int argc, const char **argv)
972 const char *servername, *printername;
973 struct cli_state *cli;
974 struct in_addr server_ip;
976 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
977 ADS_MODLIST mods = ads_init_mods(mem_ctx);
978 char *prt_dn, *srv_dn, **srv_cn;
981 if (!(ads = ads_startup())) {
986 return net_ads_printer_usage(argc, argv);
989 printername = argv[0];
992 servername = argv[1];
994 servername = global_myname();
997 /* Get printer data from SPOOLSS */
999 resolve_name(servername, &server_ip, 0x20);
1001 nt_status = cli_full_connection(&cli, global_myname(), servername,
1004 opt_user_name, opt_workgroup,
1005 opt_password ? opt_password : "",
1006 CLI_FULL_CONNECTION_USE_KERBEROS,
1009 if (NT_STATUS_IS_ERR(nt_status)) {
1010 d_printf("Unable to open a connnection to %s to obtain data "
1011 "for %s\n", servername, printername);
1016 /* Publish on AD server */
1018 ads_find_machine_acct(ads, &res, servername);
1020 if (ads_count_replies(ads, res) == 0) {
1021 d_printf("Could not find machine account for server %s\n",
1027 srv_dn = ldap_get_dn(ads->ld, res);
1028 srv_cn = ldap_explode_dn(srv_dn, 1);
1030 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
1032 cli_nt_session_open(cli, PI_SPOOLSS);
1033 get_remote_printer_publishing_data(cli, mem_ctx, &mods, printername);
1035 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1036 if (!ADS_ERR_OK(rc)) {
1037 d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
1042 d_printf("published printer\n");
1048 static int net_ads_printer_remove(int argc, const char **argv)
1052 const char *servername;
1056 if (!(ads = ads_startup())) {
1061 return net_ads_printer_usage(argc, argv);
1065 servername = argv[1];
1067 servername = global_myname();
1070 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1072 if (!ADS_ERR_OK(rc)) {
1073 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
1074 ads_msgfree(ads, res);
1079 if (ads_count_replies(ads, res) == 0) {
1080 d_printf("Printer '%s' not found\n", argv[1]);
1081 ads_msgfree(ads, res);
1086 prt_dn = ads_get_dn(ads, res);
1087 ads_msgfree(ads, res);
1088 rc = ads_del_dn(ads, prt_dn);
1089 ads_memfree(ads, prt_dn);
1091 if (!ADS_ERR_OK(rc)) {
1092 d_printf("ads_del_dn: %s\n", ads_errstr(rc));
1101 static int net_ads_printer(int argc, const char **argv)
1103 struct functable func[] = {
1104 {"SEARCH", net_ads_printer_search},
1105 {"INFO", net_ads_printer_info},
1106 {"PUBLISH", net_ads_printer_publish},
1107 {"REMOVE", net_ads_printer_remove},
1111 return net_run_function(argc, argv, func, net_ads_printer_usage);
1115 static int net_ads_password(int argc, const char **argv)
1118 const char *auth_principal = opt_user_name;
1119 const char *auth_password = opt_password;
1121 char *new_password = NULL;
1126 if (opt_user_name == NULL || opt_password == NULL) {
1127 d_printf("You must supply an administrator username/password\n");
1132 d_printf("ERROR: You must say which username to change password for\n");
1137 if (!strchr_m(user, '@')) {
1138 asprintf(&c, "%s@%s", argv[0], lp_realm());
1142 use_in_memory_ccache();
1143 c = strchr_m(auth_principal, '@');
1150 /* use the realm so we can eventually change passwords for users
1151 in realms other than default */
1152 if (!(ads = ads_init(realm, NULL, NULL))) {
1156 /* we don't actually need a full connect, but it's the easy way to
1157 fill in the KDC's addresss */
1160 if (!ads || !ads->config.realm) {
1161 d_printf("Didn't find the kerberos server!\n");
1166 new_password = (char *)argv[1];
1168 asprintf(&prompt, "Enter new password for %s:", user);
1169 new_password = getpass(prompt);
1173 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1174 auth_password, user, new_password, ads->auth.time_offset);
1175 if (!ADS_ERR_OK(ret)) {
1176 d_printf("Password change failed :-( ...\n");
1181 d_printf("Password change for %s completed.\n", user);
1187 int net_ads_changetrustpw(int argc, const char **argv)
1190 char *host_principal;
1194 if (!secrets_init()) {
1195 DEBUG(1,("Failed to initialise secrets database\n"));
1199 net_use_machine_password();
1201 use_in_memory_ccache();
1203 if (!(ads = ads_startup())) {
1207 fstrcpy(my_name, global_myname());
1208 strlower_m(my_name);
1209 asprintf(&host_principal, "%s@%s", my_name, ads->config.realm);
1210 d_printf("Changing password for principal: HOST/%s\n", host_principal);
1212 ret = ads_change_trust_account_password(ads, host_principal);
1214 if (!ADS_ERR_OK(ret)) {
1215 d_printf("Password change failed :-( ...\n");
1217 SAFE_FREE(host_principal);
1221 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
1223 if (lp_use_kerberos_keytab()) {
1224 d_printf("Attempting to update system keytab with new password.\n");
1225 if (ads_keytab_create_default(ads)) {
1226 d_printf("Failed to update system keytab.\n");
1231 SAFE_FREE(host_principal);
1237 help for net ads search
1239 static int net_ads_search_usage(int argc, const char **argv)
1242 "\nnet ads search <expression> <attributes...>\n"\
1243 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1244 "The expression is a standard LDAP search expression, and the\n"\
1245 "attributes are a list of LDAP fields to show in the results\n\n"\
1246 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1248 net_common_flags_usage(argc, argv);
1254 general ADS search function. Useful in diagnosing problems in ADS
1256 static int net_ads_search(int argc, const char **argv)
1260 const char *ldap_exp;
1265 return net_ads_search_usage(argc, argv);
1268 if (!(ads = ads_startup())) {
1275 rc = ads_do_search_all(ads, ads->config.bind_path,
1277 ldap_exp, attrs, &res);
1278 if (!ADS_ERR_OK(rc)) {
1279 d_printf("search failed: %s\n", ads_errstr(rc));
1284 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1286 /* dump the results */
1289 ads_msgfree(ads, res);
1297 help for net ads search
1299 static int net_ads_dn_usage(int argc, const char **argv)
1302 "\nnet ads dn <dn> <attributes...>\n"\
1303 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1304 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1305 "to show in the results\n\n"\
1306 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1308 net_common_flags_usage(argc, argv);
1314 general ADS search function. Useful in diagnosing problems in ADS
1316 static int net_ads_dn(int argc, const char **argv)
1325 return net_ads_dn_usage(argc, argv);
1328 if (!(ads = ads_startup())) {
1335 rc = ads_do_search_all(ads, dn,
1337 "(objectclass=*)", attrs, &res);
1338 if (!ADS_ERR_OK(rc)) {
1339 d_printf("search failed: %s\n", ads_errstr(rc));
1344 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1346 /* dump the results */
1349 ads_msgfree(ads, res);
1355 static int net_ads_keytab_usage(int argc, const char **argv)
1358 "net ads keytab <COMMAND>\n"\
1359 "<COMMAND> can be either:\n"\
1360 " CREATE Creates a fresh keytab\n"\
1361 " ADD Adds new service principal\n"\
1362 " FLUSH Flushes out all keytab entries\n"\
1363 " HELP Prints this help message\n"\
1364 "The ADD command will take arguments, the other commands\n"\
1365 "will not take any arguments. The arguments given to ADD\n"\
1366 "should be a list of principals to add. For example, \n"\
1367 " net ads keytab add srv1 srv2\n"\
1368 "will add principals for the services srv1 and srv2 to the\n"\
1369 "system's keytab.\n"\
1375 static int net_ads_keytab_flush(int argc, const char **argv)
1380 if (!(ads = ads_startup())) {
1383 ret = ads_keytab_flush(ads);
1388 static int net_ads_keytab_add(int argc, const char **argv)
1394 d_printf("Processing principals to add...\n");
1395 if (!(ads = ads_startup())) {
1398 for (i = 0; i < argc; i++) {
1399 ret |= ads_keytab_add_entry(ads, argv[i]);
1405 static int net_ads_keytab_create(int argc, const char **argv)
1410 if (!(ads = ads_startup())) {
1413 ret = ads_keytab_create_default(ads);
1418 int net_ads_keytab(int argc, const char **argv)
1420 struct functable func[] = {
1421 {"CREATE", net_ads_keytab_create},
1422 {"ADD", net_ads_keytab_add},
1423 {"FLUSH", net_ads_keytab_flush},
1424 {"HELP", net_ads_keytab_usage},
1428 if (!lp_use_kerberos_keytab()) {
1429 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
1430 use keytab functions.\n");
1433 return net_run_function(argc, argv, func, net_ads_keytab_usage);
1436 int net_ads_help(int argc, const char **argv)
1438 struct functable func[] = {
1439 {"USER", net_ads_user_usage},
1440 {"GROUP", net_ads_group_usage},
1441 {"PRINTER", net_ads_printer_usage},
1442 {"SEARCH", net_ads_search_usage},
1444 {"INFO", net_ads_info},
1445 {"JOIN", net_ads_join},
1446 {"LEAVE", net_ads_leave},
1447 {"STATUS", net_ads_status},
1448 {"PASSWORD", net_ads_password},
1449 {"CHANGETRUSTPW", net_ads_changetrustpw},
1454 return net_run_function(argc, argv, func, net_ads_usage);
1457 int net_ads(int argc, const char **argv)
1459 struct functable func[] = {
1460 {"INFO", net_ads_info},
1461 {"JOIN", net_ads_join},
1462 {"TESTJOIN", net_ads_testjoin},
1463 {"LEAVE", net_ads_leave},
1464 {"STATUS", net_ads_status},
1465 {"USER", net_ads_user},
1466 {"GROUP", net_ads_group},
1467 {"PASSWORD", net_ads_password},
1468 {"CHANGETRUSTPW", net_ads_changetrustpw},
1469 {"PRINTER", net_ads_printer},
1470 {"SEARCH", net_ads_search},
1472 {"WORKGROUP", net_ads_workgroup},
1473 {"LOOKUP", net_ads_lookup},
1474 {"KEYTAB", net_ads_keytab},
1475 {"HELP", net_ads_help},
1479 return net_run_function(argc, argv, func, net_ads_usage);
1484 static int net_ads_noads(void)
1486 d_printf("ADS support not compiled in\n");
1490 int net_ads_keytab(int argc, const char **argv)
1492 return net_ads_noads();
1495 int net_ads_usage(int argc, const char **argv)
1497 return net_ads_noads();
1500 int net_ads_help(int argc, const char **argv)
1502 return net_ads_noads();
1505 int net_ads_changetrustpw(int argc, const char **argv)
1507 return net_ads_noads();
1510 int net_ads_join(int argc, const char **argv)
1512 return net_ads_noads();
1515 int net_ads_user(int argc, const char **argv)
1517 return net_ads_noads();
1520 int net_ads_group(int argc, const char **argv)
1522 return net_ads_noads();
1525 /* this one shouldn't display a message */
1526 int net_ads_check(void)
1531 int net_ads(int argc, const char **argv)
1533 return net_ads_usage(argc, argv);