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)
74 ads = ads_init(NULL, opt_target_workgroup, opt_host);
76 ads->auth.flags |= ADS_AUTH_NO_BIND;
79 status = ads_connect(ads);
80 if (!ADS_ERR_OK(status) || !ads) {
81 d_fprintf(stderr, "Didn't find the cldap server!\n");
85 if (!ads->config.realm) {
86 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
90 return ads_cldap_netlogon(ads);
95 static int net_ads_info(int argc, const char **argv)
99 /* if netbios is disabled we have to default to the realm from smb.conf */
101 if ( lp_disable_netbios() && *lp_realm() )
102 ads = ads_init(lp_realm(), opt_target_workgroup, opt_host);
104 ads = ads_init(NULL, opt_target_workgroup, opt_host);
107 ads->auth.flags |= ADS_AUTH_NO_BIND;
112 if (!ads || !ads->config.realm) {
113 d_fprintf(stderr, "Didn't find the ldap server!\n");
117 d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
118 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
119 d_printf("Realm: %s\n", ads->config.realm);
120 d_printf("Bind Path: %s\n", ads->config.bind_path);
121 d_printf("LDAP port: %d\n", ads->ldap_port);
122 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
124 d_printf("KDC server: %s\n", ads->auth.kdc_server );
125 d_printf("Server time offset: %d\n", ads->auth.time_offset );
130 static void use_in_memory_ccache(void) {
131 /* Use in-memory credentials cache so we do not interfere with
132 * existing credentials */
133 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
136 static ADS_STRUCT *ads_startup(void)
140 BOOL need_password = False;
141 BOOL second_time = False;
144 /* lp_realm() should be handled by a command line param,
145 However, the join requires that realm be set in smb.conf
146 and compares our realm with the remote server's so this is
147 ok until someone needs more flexibility */
149 ads = ads_init(lp_realm(), opt_target_workgroup, opt_host);
151 if (!opt_user_name) {
152 opt_user_name = "administrator";
155 if (opt_user_specified) {
156 need_password = True;
160 if (!opt_password && need_password && !opt_machine_pass) {
162 asprintf(&prompt,"%s's password: ", opt_user_name);
163 opt_password = getpass(prompt);
168 use_in_memory_ccache();
169 ads->auth.password = smb_xstrdup(opt_password);
172 ads->auth.user_name = smb_xstrdup(opt_user_name);
175 * If the username is of the form "name@realm",
176 * extract the realm and convert to upper case.
177 * This is only used to establish the connection.
179 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
181 ads->auth.realm = smb_xstrdup(cp);
182 strupper_m(ads->auth.realm);
185 status = ads_connect(ads);
187 if (!ADS_ERR_OK(status)) {
188 if (!need_password && !second_time) {
189 need_password = True;
193 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
202 Check to see if connection can be made via ads.
203 ads_startup() stores the password in opt_password if it needs to so
204 that rpc or rap can use it without re-prompting.
206 int net_ads_check(void)
218 determine the netbios workgroup name for a domain
220 static int net_ads_workgroup(int argc, const char **argv)
224 const char *workgroup;
226 if (!(ads = ads_startup())) return -1;
228 if (!(ctx = talloc_init("net_ads_workgroup"))) {
233 if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
234 d_fprintf(stderr, "Failed to find workgroup for realm '%s'\n",
241 d_printf("Workgroup: %s\n", workgroup);
250 static BOOL usergrp_display(char *field, void **values, void *data_area)
252 char **disp_fields = (char **) data_area;
254 if (!field) { /* must be end of record */
255 if (disp_fields[0]) {
256 if (!strchr_m(disp_fields[0], '$')) {
258 d_printf("%-21.21s %s\n",
259 disp_fields[0], disp_fields[1]);
261 d_printf("%s\n", disp_fields[0]);
264 SAFE_FREE(disp_fields[0]);
265 SAFE_FREE(disp_fields[1]);
268 if (!values) /* must be new field, indicate string field */
270 if (StrCaseCmp(field, "sAMAccountName") == 0) {
271 disp_fields[0] = SMB_STRDUP((char *) values[0]);
273 if (StrCaseCmp(field, "description") == 0)
274 disp_fields[1] = SMB_STRDUP((char *) values[0]);
278 static int net_ads_user_usage(int argc, const char **argv)
280 return net_help_user(argc, argv);
283 static int ads_user_add(int argc, const char **argv)
291 if (argc < 1) return net_ads_user_usage(argc, argv);
293 if (!(ads = ads_startup())) {
297 status = ads_find_user_acct(ads, &res, argv[0]);
299 if (!ADS_ERR_OK(status)) {
300 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
304 if (ads_count_replies(ads, res)) {
305 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
309 if (opt_container == NULL) {
310 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
313 status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
315 if (!ADS_ERR_OK(status)) {
316 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
321 /* if no password is to be set, we're done */
323 d_printf("User %s added\n", argv[0]);
328 /* try setting the password */
329 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
330 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
331 ads->auth.time_offset);
333 if (ADS_ERR_OK(status)) {
334 d_printf("User %s added\n", argv[0]);
339 /* password didn't set, delete account */
340 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
341 argv[0], ads_errstr(status));
342 ads_msgfree(ads, res);
343 status=ads_find_user_acct(ads, &res, argv[0]);
344 if (ADS_ERR_OK(status)) {
345 userdn = ads_get_dn(ads, res);
346 ads_del_dn(ads, userdn);
347 ads_memfree(ads, userdn);
352 ads_msgfree(ads, res);
357 static int ads_user_info(int argc, const char **argv)
362 const char *attrs[] = {"memberOf", NULL};
363 char *searchstring=NULL;
368 return net_ads_user_usage(argc, argv);
371 escaped_user = escape_ldap_string_alloc(argv[0]);
374 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
378 if (!(ads = ads_startup())) {
379 SAFE_FREE(escaped_user);
383 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
384 rc = ads_search(ads, &res, searchstring, attrs);
385 safe_free(searchstring);
387 if (!ADS_ERR_OK(rc)) {
388 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
390 SAFE_FREE(escaped_user);
394 grouplist = ldap_get_values(ads->ld, res, "memberOf");
399 for (i=0;grouplist[i];i++) {
400 groupname = ldap_explode_dn(grouplist[i], 1);
401 d_printf("%s\n", groupname[0]);
402 ldap_value_free(groupname);
404 ldap_value_free(grouplist);
407 ads_msgfree(ads, res);
409 SAFE_FREE(escaped_user);
413 static int ads_user_delete(int argc, const char **argv)
421 return net_ads_user_usage(argc, argv);
424 if (!(ads = ads_startup())) {
428 rc = ads_find_user_acct(ads, &res, argv[0]);
429 if (!ADS_ERR_OK(rc)) {
430 DEBUG(0, ("User %s does not exist\n", argv[0]));
434 userdn = ads_get_dn(ads, res);
435 ads_msgfree(ads, res);
436 rc = ads_del_dn(ads, userdn);
437 ads_memfree(ads, userdn);
438 if (!ADS_ERR_OK(rc)) {
439 d_printf("User %s deleted\n", argv[0]);
443 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
449 int net_ads_user(int argc, const char **argv)
451 struct functable func[] = {
452 {"ADD", ads_user_add},
453 {"INFO", ads_user_info},
454 {"DELETE", ads_user_delete},
459 const char *shortattrs[] = {"sAMAccountName", NULL};
460 const char *longattrs[] = {"sAMAccountName", "description", NULL};
461 char *disp_fields[2] = {NULL, NULL};
464 if (!(ads = ads_startup())) {
468 if (opt_long_list_entries)
469 d_printf("\nUser name Comment"\
470 "\n-----------------------------\n");
472 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
474 "(objectclass=user)",
475 opt_long_list_entries ? longattrs :
476 shortattrs, usergrp_display,
482 return net_run_function(argc, argv, func, net_ads_user_usage);
485 static int net_ads_group_usage(int argc, const char **argv)
487 return net_help_group(argc, argv);
490 static int ads_group_add(int argc, const char **argv)
498 return net_ads_group_usage(argc, argv);
501 if (!(ads = ads_startup())) {
505 status = ads_find_user_acct(ads, &res, argv[0]);
507 if (!ADS_ERR_OK(status)) {
508 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
512 if (ads_count_replies(ads, res)) {
513 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
514 ads_msgfree(ads, res);
518 if (opt_container == NULL) {
519 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
522 status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
524 if (ADS_ERR_OK(status)) {
525 d_printf("Group %s added\n", argv[0]);
528 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
534 ads_msgfree(ads, res);
539 static int ads_group_delete(int argc, const char **argv)
547 return net_ads_group_usage(argc, argv);
550 if (!(ads = ads_startup())) {
554 rc = ads_find_user_acct(ads, &res, argv[0]);
555 if (!ADS_ERR_OK(rc)) {
556 DEBUG(0, ("Group %s does not exist\n", argv[0]));
560 groupdn = ads_get_dn(ads, res);
561 ads_msgfree(ads, res);
562 rc = ads_del_dn(ads, groupdn);
563 ads_memfree(ads, groupdn);
564 if (!ADS_ERR_OK(rc)) {
565 d_printf("Group %s deleted\n", argv[0]);
569 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
575 int net_ads_group(int argc, const char **argv)
577 struct functable func[] = {
578 {"ADD", ads_group_add},
579 {"DELETE", ads_group_delete},
584 const char *shortattrs[] = {"sAMAccountName", NULL};
585 const char *longattrs[] = {"sAMAccountName", "description", NULL};
586 char *disp_fields[2] = {NULL, NULL};
589 if (!(ads = ads_startup())) {
593 if (opt_long_list_entries)
594 d_printf("\nGroup name Comment"\
595 "\n-----------------------------\n");
596 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
598 "(objectclass=group)",
599 opt_long_list_entries ? longattrs :
600 shortattrs, usergrp_display,
606 return net_run_function(argc, argv, func, net_ads_group_usage);
609 static int net_ads_status(int argc, const char **argv)
615 if (!(ads = ads_startup())) {
619 rc = ads_find_machine_acct(ads, &res, global_myname());
620 if (!ADS_ERR_OK(rc)) {
621 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
626 if (ads_count_replies(ads, res) == 0) {
627 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
637 static int net_ads_leave(int argc, const char **argv)
639 ADS_STRUCT *ads = NULL;
642 if (!secrets_init()) {
643 DEBUG(1,("Failed to initialise secrets database\n"));
648 net_use_machine_password();
651 if (!(ads = ads_startup())) {
655 rc = ads_leave_realm(ads, global_myname());
656 if (!ADS_ERR_OK(rc)) {
657 d_fprintf(stderr, "Failed to delete host '%s' from the '%s' realm.\n",
658 global_myname(), ads->config.realm);
663 d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
668 static int net_ads_join_ok(void)
670 ADS_STRUCT *ads = NULL;
672 if (!secrets_init()) {
673 DEBUG(1,("Failed to initialise secrets database\n"));
677 net_use_machine_password();
679 if (!(ads = ads_startup())) {
688 check that an existing join is OK
690 int net_ads_testjoin(int argc, const char **argv)
692 use_in_memory_ccache();
694 /* Display success or failure */
695 if (net_ads_join_ok() != 0) {
696 fprintf(stderr,"Join to domain is not valid\n");
700 printf("Join is OK\n");
705 join a domain using ADS
707 int net_ads_join(int argc, const char **argv)
712 char *machine_account = NULL;
714 const char *org_unit = NULL;
719 uint32 sec_channel_type = SEC_CHAN_WKSTA;
720 uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT;
721 const char *short_domain_name = NULL;
722 TALLOC_CTX *ctx = NULL;
724 if (lp_server_role() == ROLE_STANDALONE) {
725 d_printf("cannot join as standalone machine\n");
729 if (strlen(global_myname()) > 15) {
730 d_printf("Our netbios name can only be 15 chars long, \"%s\""
731 " is %d chars long\n",
732 global_myname(), strlen(global_myname()));
740 if (!secrets_init()) {
741 DEBUG(1,("Failed to initialise secrets database\n"));
745 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
746 password = SMB_STRDUP(tmp_password);
748 if (!(ads = ads_startup())) {
753 d_fprintf(stderr, "realm must be set in in smb.conf for ADS join to succeed.\n");
758 if (strcmp(ads->config.realm, lp_realm()) != 0) {
759 d_fprintf(stderr, "realm of remote server (%s) and realm in smb.conf (%s) DO NOT match. Aborting join\n", ads->config.realm, lp_realm());
764 ou_str = ads_ou_string(ads,org_unit);
765 asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
768 rc = ads_search_dn(ads, &res, dn, NULL);
769 ads_msgfree(ads, res);
771 if (rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
772 d_fprintf(stderr, "ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
779 if (!ADS_ERR_OK(rc)) {
780 d_fprintf(stderr, "ads_join_realm: %s\n", ads_errstr(rc));
785 rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
786 if (!ADS_ERR_OK(rc)) {
787 d_fprintf(stderr, "ads_join_realm: %s\n", ads_errstr(rc));
792 rc = ads_domain_sid(ads, &dom_sid);
793 if (!ADS_ERR_OK(rc)) {
794 d_fprintf(stderr, "ads_domain_sid: %s\n", ads_errstr(rc));
799 if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
800 d_fprintf(stderr, "asprintf failed\n");
805 rc = ads_set_machine_password(ads, machine_account, password);
806 if (!ADS_ERR_OK(rc)) {
807 d_fprintf(stderr, "ads_set_machine_password: %s\n", ads_errstr(rc));
812 /* make sure we get the right workgroup */
814 if ( !(ctx = talloc_init("net ads join")) ) {
815 d_fprintf(stderr, "talloc_init() failed!\n");
820 rc = ads_workgroup_name(ads, ctx, &short_domain_name);
821 if ( ADS_ERR_OK(rc) ) {
822 if ( !strequal(lp_workgroup(), short_domain_name) ) {
823 d_printf("The workgroup in smb.conf does not match the short\n");
824 d_printf("domain name obtained from the server.\n");
825 d_printf("Using the name [%s] from the server.\n", short_domain_name);
826 d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
829 short_domain_name = lp_workgroup();
832 d_printf("Using short domain name -- %s\n", short_domain_name);
834 /* HACK ALRET! Store the sid and password under bother the lp_workgroup()
835 value from smb.conf and the string returned from the server. The former is
836 neede to bootstrap winbindd's first connection to the DC to get the real
837 short domain name --jerry */
839 if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
840 DEBUG(1,("Failed to save domain sid\n"));
845 if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
846 DEBUG(1,("Failed to save machine password\n"));
852 if (!kerberos_derive_salting_principal(machine_account)) {
853 DEBUG(1,("Failed to determine salting principal\n"));
858 if (!kerberos_derive_cifs_salting_principals()) {
859 DEBUG(1,("Failed to determine salting principals\n"));
865 if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) {
866 DEBUG(1,("Failed to save domain sid\n"));
871 if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) {
872 DEBUG(1,("Failed to save machine password\n"));
877 /* Now build the keytab, using the same ADS connection */
878 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
879 DEBUG(1,("Error creating host keytab!\n"));
882 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
885 SAFE_FREE(machine_account);
893 int net_ads_printer_usage(int argc, const char **argv)
896 "\nnet ads printer search <printer>"
897 "\n\tsearch for a printer in the directory\n"
898 "\nnet ads printer info <printer> <server>"
899 "\n\tlookup info in directory for printer on server"
900 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
901 "\nnet ads printer publish <printername>"
902 "\n\tpublish printer in directory"
903 "\n\t(note: printer name is required)\n"
904 "\nnet ads printer remove <printername>"
905 "\n\tremove printer from directory"
906 "\n\t(note: printer name is required)\n");
910 static int net_ads_printer_search(int argc, const char **argv)
916 if (!(ads = ads_startup())) {
920 rc = ads_find_printers(ads, &res);
922 if (!ADS_ERR_OK(rc)) {
923 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
924 ads_msgfree(ads, res);
929 if (ads_count_replies(ads, res) == 0) {
930 d_fprintf(stderr, "No results found\n");
931 ads_msgfree(ads, res);
937 ads_msgfree(ads, res);
942 static int net_ads_printer_info(int argc, const char **argv)
946 const char *servername, *printername;
949 if (!(ads = ads_startup())) {
954 printername = argv[0];
960 servername = argv[1];
962 servername = global_myname();
965 rc = ads_find_printer_on_server(ads, &res, printername, servername);
967 if (!ADS_ERR_OK(rc)) {
968 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
969 ads_msgfree(ads, res);
974 if (ads_count_replies(ads, res) == 0) {
975 d_fprintf(stderr, "Printer '%s' not found\n", printername);
976 ads_msgfree(ads, res);
982 ads_msgfree(ads, res);
988 void do_drv_upgrade_printer(int msg_type, struct process_id src,
989 void *buf, size_t len)
994 static int net_ads_printer_publish(int argc, const char **argv)
998 const char *servername, *printername;
999 struct cli_state *cli;
1000 struct rpc_pipe_client *pipe_hnd;
1001 struct in_addr server_ip;
1003 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1004 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1005 char *prt_dn, *srv_dn, **srv_cn;
1008 if (!(ads = ads_startup())) {
1013 return net_ads_printer_usage(argc, argv);
1016 printername = argv[0];
1019 servername = argv[1];
1021 servername = global_myname();
1024 /* Get printer data from SPOOLSS */
1026 resolve_name(servername, &server_ip, 0x20);
1028 nt_status = cli_full_connection(&cli, global_myname(), servername,
1031 opt_user_name, opt_workgroup,
1032 opt_password ? opt_password : "",
1033 CLI_FULL_CONNECTION_USE_KERBEROS,
1036 if (NT_STATUS_IS_ERR(nt_status)) {
1037 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1038 "for %s\n", servername, printername);
1043 /* Publish on AD server */
1045 ads_find_machine_acct(ads, &res, servername);
1047 if (ads_count_replies(ads, res) == 0) {
1048 d_fprintf(stderr, "Could not find machine account for server %s\n",
1054 srv_dn = ldap_get_dn(ads->ld, res);
1055 srv_cn = ldap_explode_dn(srv_dn, 1);
1057 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
1059 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1061 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1067 get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1070 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1071 if (!ADS_ERR_OK(rc)) {
1072 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1077 d_printf("published printer\n");
1083 static int net_ads_printer_remove(int argc, const char **argv)
1087 const char *servername;
1091 if (!(ads = ads_startup())) {
1096 return net_ads_printer_usage(argc, argv);
1100 servername = argv[1];
1102 servername = global_myname();
1105 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1107 if (!ADS_ERR_OK(rc)) {
1108 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1109 ads_msgfree(ads, res);
1114 if (ads_count_replies(ads, res) == 0) {
1115 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1116 ads_msgfree(ads, res);
1121 prt_dn = ads_get_dn(ads, res);
1122 ads_msgfree(ads, res);
1123 rc = ads_del_dn(ads, prt_dn);
1124 ads_memfree(ads, prt_dn);
1126 if (!ADS_ERR_OK(rc)) {
1127 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1136 static int net_ads_printer(int argc, const char **argv)
1138 struct functable func[] = {
1139 {"SEARCH", net_ads_printer_search},
1140 {"INFO", net_ads_printer_info},
1141 {"PUBLISH", net_ads_printer_publish},
1142 {"REMOVE", net_ads_printer_remove},
1146 return net_run_function(argc, argv, func, net_ads_printer_usage);
1150 static int net_ads_password(int argc, const char **argv)
1153 const char *auth_principal = opt_user_name;
1154 const char *auth_password = opt_password;
1156 char *new_password = NULL;
1161 if (opt_user_name == NULL || opt_password == NULL) {
1162 d_fprintf(stderr, "You must supply an administrator username/password\n");
1167 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1172 if (!strchr_m(user, '@')) {
1173 asprintf(&c, "%s@%s", argv[0], lp_realm());
1177 use_in_memory_ccache();
1178 c = strchr_m(auth_principal, '@');
1185 /* use the realm so we can eventually change passwords for users
1186 in realms other than default */
1187 if (!(ads = ads_init(realm, NULL, NULL))) {
1191 /* we don't actually need a full connect, but it's the easy way to
1192 fill in the KDC's addresss */
1195 if (!ads || !ads->config.realm) {
1196 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1201 new_password = (char *)argv[1];
1203 asprintf(&prompt, "Enter new password for %s:", user);
1204 new_password = getpass(prompt);
1208 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1209 auth_password, user, new_password, ads->auth.time_offset);
1210 if (!ADS_ERR_OK(ret)) {
1211 d_fprintf(stderr, "Password change failed :-( ...\n");
1216 d_printf("Password change for %s completed.\n", user);
1222 int net_ads_changetrustpw(int argc, const char **argv)
1225 char *host_principal;
1229 if (!secrets_init()) {
1230 DEBUG(1,("Failed to initialise secrets database\n"));
1234 net_use_machine_password();
1236 use_in_memory_ccache();
1238 if (!(ads = ads_startup())) {
1242 fstrcpy(my_name, global_myname());
1243 strlower_m(my_name);
1244 asprintf(&host_principal, "%s@%s", my_name, ads->config.realm);
1245 d_printf("Changing password for principal: HOST/%s\n", host_principal);
1247 ret = ads_change_trust_account_password(ads, host_principal);
1249 if (!ADS_ERR_OK(ret)) {
1250 d_fprintf(stderr, "Password change failed :-( ...\n");
1252 SAFE_FREE(host_principal);
1256 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
1258 if (lp_use_kerberos_keytab()) {
1259 d_printf("Attempting to update system keytab with new password.\n");
1260 if (ads_keytab_create_default(ads)) {
1261 d_printf("Failed to update system keytab.\n");
1266 SAFE_FREE(host_principal);
1272 help for net ads search
1274 static int net_ads_search_usage(int argc, const char **argv)
1277 "\nnet ads search <expression> <attributes...>\n"\
1278 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1279 "The expression is a standard LDAP search expression, and the\n"\
1280 "attributes are a list of LDAP fields to show in the results\n\n"\
1281 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1283 net_common_flags_usage(argc, argv);
1289 general ADS search function. Useful in diagnosing problems in ADS
1291 static int net_ads_search(int argc, const char **argv)
1295 const char *ldap_exp;
1300 return net_ads_search_usage(argc, argv);
1303 if (!(ads = ads_startup())) {
1310 rc = ads_do_search_all(ads, ads->config.bind_path,
1312 ldap_exp, attrs, &res);
1313 if (!ADS_ERR_OK(rc)) {
1314 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1319 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1321 /* dump the results */
1324 ads_msgfree(ads, res);
1332 help for net ads search
1334 static int net_ads_dn_usage(int argc, const char **argv)
1337 "\nnet ads dn <dn> <attributes...>\n"\
1338 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1339 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1340 "to show in the results\n\n"\
1341 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1343 net_common_flags_usage(argc, argv);
1349 general ADS search function. Useful in diagnosing problems in ADS
1351 static int net_ads_dn(int argc, const char **argv)
1360 return net_ads_dn_usage(argc, argv);
1363 if (!(ads = ads_startup())) {
1370 rc = ads_do_search_all(ads, dn,
1372 "(objectclass=*)", attrs, &res);
1373 if (!ADS_ERR_OK(rc)) {
1374 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1379 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1381 /* dump the results */
1384 ads_msgfree(ads, res);
1390 static int net_ads_keytab_usage(int argc, const char **argv)
1393 "net ads keytab <COMMAND>\n"\
1394 "<COMMAND> can be either:\n"\
1395 " CREATE Creates a fresh keytab\n"\
1396 " ADD Adds new service principal\n"\
1397 " FLUSH Flushes out all keytab entries\n"\
1398 " HELP Prints this help message\n"\
1399 "The ADD command will take arguments, the other commands\n"\
1400 "will not take any arguments. The arguments given to ADD\n"\
1401 "should be a list of principals to add. For example, \n"\
1402 " net ads keytab add srv1 srv2\n"\
1403 "will add principals for the services srv1 and srv2 to the\n"\
1404 "system's keytab.\n"\
1410 static int net_ads_keytab_flush(int argc, const char **argv)
1415 if (!(ads = ads_startup())) {
1418 ret = ads_keytab_flush(ads);
1423 static int net_ads_keytab_add(int argc, const char **argv)
1429 d_printf("Processing principals to add...\n");
1430 if (!(ads = ads_startup())) {
1433 for (i = 0; i < argc; i++) {
1434 ret |= ads_keytab_add_entry(ads, argv[i]);
1440 static int net_ads_keytab_create(int argc, const char **argv)
1445 if (!(ads = ads_startup())) {
1448 ret = ads_keytab_create_default(ads);
1453 int net_ads_keytab(int argc, const char **argv)
1455 struct functable func[] = {
1456 {"CREATE", net_ads_keytab_create},
1457 {"ADD", net_ads_keytab_add},
1458 {"FLUSH", net_ads_keytab_flush},
1459 {"HELP", net_ads_keytab_usage},
1463 if (!lp_use_kerberos_keytab()) {
1464 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
1465 use keytab functions.\n");
1468 return net_run_function(argc, argv, func, net_ads_keytab_usage);
1471 int net_ads_help(int argc, const char **argv)
1473 struct functable func[] = {
1474 {"USER", net_ads_user_usage},
1475 {"GROUP", net_ads_group_usage},
1476 {"PRINTER", net_ads_printer_usage},
1477 {"SEARCH", net_ads_search_usage},
1479 {"INFO", net_ads_info},
1480 {"JOIN", net_ads_join},
1481 {"LEAVE", net_ads_leave},
1482 {"STATUS", net_ads_status},
1483 {"PASSWORD", net_ads_password},
1484 {"CHANGETRUSTPW", net_ads_changetrustpw},
1489 return net_run_function(argc, argv, func, net_ads_usage);
1492 int net_ads(int argc, const char **argv)
1494 struct functable func[] = {
1495 {"INFO", net_ads_info},
1496 {"JOIN", net_ads_join},
1497 {"TESTJOIN", net_ads_testjoin},
1498 {"LEAVE", net_ads_leave},
1499 {"STATUS", net_ads_status},
1500 {"USER", net_ads_user},
1501 {"GROUP", net_ads_group},
1502 {"PASSWORD", net_ads_password},
1503 {"CHANGETRUSTPW", net_ads_changetrustpw},
1504 {"PRINTER", net_ads_printer},
1505 {"SEARCH", net_ads_search},
1507 {"WORKGROUP", net_ads_workgroup},
1508 {"LOOKUP", net_ads_lookup},
1509 {"KEYTAB", net_ads_keytab},
1510 {"HELP", net_ads_help},
1514 return net_run_function(argc, argv, func, net_ads_usage);
1519 static int net_ads_noads(void)
1521 d_fprintf(stderr, "ADS support not compiled in\n");
1525 int net_ads_keytab(int argc, const char **argv)
1527 return net_ads_noads();
1530 int net_ads_usage(int argc, const char **argv)
1532 return net_ads_noads();
1535 int net_ads_help(int argc, const char **argv)
1537 return net_ads_noads();
1540 int net_ads_changetrustpw(int argc, const char **argv)
1542 return net_ads_noads();
1545 int net_ads_join(int argc, const char **argv)
1547 return net_ads_noads();
1550 int net_ads_user(int argc, const char **argv)
1552 return net_ads_noads();
1555 int net_ads_group(int argc, const char **argv)
1557 return net_ads_noads();
1560 /* this one shouldn't display a message */
1561 int net_ads_check(void)
1566 int net_ads(int argc, const char **argv)
1568 return net_ads_usage(argc, argv);