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
;
80 if (!ads
|| !ads
->config
.realm
) {
81 d_printf("Didn't find the cldap server!\n");
85 return ads_cldap_netlogon(ads
);
90 static int net_ads_info(int argc
, const char **argv
)
94 ads
= ads_init(NULL
, opt_target_workgroup
, opt_host
);
97 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
102 if (!ads
|| !ads
->config
.realm
) {
103 d_printf("Didn't find the ldap server!\n");
107 d_printf("LDAP server: %s\n", inet_ntoa(ads
->ldap_ip
));
108 d_printf("LDAP server name: %s\n", ads
->config
.ldap_server_name
);
109 d_printf("Realm: %s\n", ads
->config
.realm
);
110 d_printf("Bind Path: %s\n", ads
->config
.bind_path
);
111 d_printf("LDAP port: %d\n", ads
->ldap_port
);
112 d_printf("Server time: %s\n", http_timestring(ads
->config
.current_time
));
114 d_printf("KDC server: %s\n", ads
->auth
.kdc_server
);
115 d_printf("Server time offset: %d\n", ads
->auth
.time_offset
);
120 static void use_in_memory_ccache(void) {
121 /* Use in-memory credentials cache so we do not interfere with
122 * existing credentials */
123 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
126 static ADS_STRUCT
*ads_startup(void)
130 BOOL need_password
= False
;
131 BOOL second_time
= False
;
134 /* lp_realm() should be handled by a command line param,
135 However, the join requires that realm be set in smb.conf
136 and compares our realm with the remote server's so this is
137 ok until someone needs more flexibility */
139 ads
= ads_init(lp_realm(), opt_target_workgroup
, opt_host
);
141 if (!opt_user_name
) {
142 opt_user_name
= "administrator";
145 if (opt_user_specified
) {
146 need_password
= True
;
150 if (!opt_password
&& need_password
&& !opt_machine_pass
) {
152 asprintf(&prompt
,"%s's password: ", opt_user_name
);
153 opt_password
= getpass(prompt
);
158 use_in_memory_ccache();
159 ads
->auth
.password
= smb_xstrdup(opt_password
);
162 ads
->auth
.user_name
= smb_xstrdup(opt_user_name
);
165 * If the username is of the form "name@realm",
166 * extract the realm and convert to upper case.
167 * This is only used to establish the connection.
169 if ((cp
= strchr(ads
->auth
.user_name
, '@'))!=0) {
171 ads
->auth
.realm
= smb_xstrdup(cp
);
172 strupper_m(ads
->auth
.realm
);
175 status
= ads_connect(ads
);
177 if (!ADS_ERR_OK(status
)) {
178 if (!need_password
&& !second_time
) {
179 need_password
= True
;
183 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
192 Check to see if connection can be made via ads.
193 ads_startup() stores the password in opt_password if it needs to so
194 that rpc or rap can use it without re-prompting.
196 int net_ads_check(void)
208 determine the netbios workgroup name for a domain
210 static int net_ads_workgroup(int argc
, const char **argv
)
214 const char *workgroup
;
216 if (!(ads
= ads_startup())) return -1;
218 if (!(ctx
= talloc_init("net_ads_workgroup"))) {
223 if (!ADS_ERR_OK(ads_workgroup_name(ads
, ctx
, &workgroup
))) {
224 d_printf("Failed to find workgroup for realm '%s'\n",
231 d_printf("Workgroup: %s\n", workgroup
);
240 static BOOL
usergrp_display(char *field
, void **values
, void *data_area
)
242 char **disp_fields
= (char **) data_area
;
244 if (!field
) { /* must be end of record */
245 if (!strchr_m(disp_fields
[0], '$')) {
247 d_printf("%-21.21s %s\n",
248 disp_fields
[0], disp_fields
[1]);
250 d_printf("%s\n", disp_fields
[0]);
252 SAFE_FREE(disp_fields
[0]);
253 SAFE_FREE(disp_fields
[1]);
256 if (!values
) /* must be new field, indicate string field */
258 if (StrCaseCmp(field
, "sAMAccountName") == 0) {
259 disp_fields
[0] = strdup((char *) values
[0]);
261 if (StrCaseCmp(field
, "description") == 0)
262 disp_fields
[1] = strdup((char *) values
[0]);
266 static int net_ads_user_usage(int argc
, const char **argv
)
268 return net_help_user(argc
, argv
);
271 static int ads_user_add(int argc
, const char **argv
)
279 if (argc
< 1) return net_ads_user_usage(argc
, argv
);
281 if (!(ads
= ads_startup())) {
285 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
287 if (!ADS_ERR_OK(status
)) {
288 d_printf("ads_user_add: %s\n", ads_errstr(status
));
292 if (ads_count_replies(ads
, res
)) {
293 d_printf("ads_user_add: User %s already exists\n", argv
[0]);
297 status
= ads_add_user_acct(ads
, argv
[0], opt_container
, opt_comment
);
299 if (!ADS_ERR_OK(status
)) {
300 d_printf("Could not add user %s: %s\n", argv
[0],
305 /* if no password is to be set, we're done */
307 d_printf("User %s added\n", argv
[0]);
312 /* try setting the password */
313 asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
);
314 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
315 ads
->auth
.time_offset
);
317 if (ADS_ERR_OK(status
)) {
318 d_printf("User %s added\n", argv
[0]);
323 /* password didn't set, delete account */
324 d_printf("Could not add user %s. Error setting password %s\n",
325 argv
[0], ads_errstr(status
));
326 ads_msgfree(ads
, res
);
327 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
328 if (ADS_ERR_OK(status
)) {
329 userdn
= ads_get_dn(ads
, res
);
330 ads_del_dn(ads
, userdn
);
331 ads_memfree(ads
, userdn
);
336 ads_msgfree(ads
, res
);
341 static int ads_user_info(int argc
, const char **argv
)
346 const char *attrs
[] = {"memberOf", NULL
};
347 char *searchstring
=NULL
;
349 char *escaped_user
= escape_ldap_string_alloc(argv
[0]);
352 return net_ads_user_usage(argc
, argv
);
355 if (!(ads
= ads_startup())) {
360 d_printf("ads_user_info: failed to escape user %s\n", argv
[0]);
365 asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
);
366 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
367 safe_free(searchstring
);
369 if (!ADS_ERR_OK(rc
)) {
370 d_printf("ads_search: %s\n", ads_errstr(rc
));
375 grouplist
= ldap_get_values(ads
->ld
, res
, "memberOf");
380 for (i
=0;grouplist
[i
];i
++) {
381 groupname
= ldap_explode_dn(grouplist
[i
], 1);
382 d_printf("%s\n", groupname
[0]);
383 ldap_value_free(groupname
);
385 ldap_value_free(grouplist
);
388 ads_msgfree(ads
, res
);
393 static int ads_user_delete(int argc
, const char **argv
)
401 return net_ads_user_usage(argc
, argv
);
404 if (!(ads
= ads_startup())) {
408 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
409 if (!ADS_ERR_OK(rc
)) {
410 DEBUG(0, ("User %s does not exist\n", argv
[0]));
414 userdn
= ads_get_dn(ads
, res
);
415 ads_msgfree(ads
, res
);
416 rc
= ads_del_dn(ads
, userdn
);
417 ads_memfree(ads
, userdn
);
418 if (!ADS_ERR_OK(rc
)) {
419 d_printf("User %s deleted\n", argv
[0]);
423 d_printf("Error deleting user %s: %s\n", argv
[0],
429 int net_ads_user(int argc
, const char **argv
)
431 struct functable func
[] = {
432 {"ADD", ads_user_add
},
433 {"INFO", ads_user_info
},
434 {"DELETE", ads_user_delete
},
439 const char *shortattrs
[] = {"sAMAccountName", NULL
};
440 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
441 char *disp_fields
[2] = {NULL
, NULL
};
444 if (!(ads
= ads_startup())) {
448 if (opt_long_list_entries
)
449 d_printf("\nUser name Comment"\
450 "\n-----------------------------\n");
452 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
454 "(objectclass=user)",
455 opt_long_list_entries
? longattrs
:
456 shortattrs
, usergrp_display
,
462 return net_run_function(argc
, argv
, func
, net_ads_user_usage
);
465 static int net_ads_group_usage(int argc
, const char **argv
)
467 return net_help_group(argc
, argv
);
470 static int ads_group_add(int argc
, const char **argv
)
478 return net_ads_group_usage(argc
, argv
);
481 if (!(ads
= ads_startup())) {
485 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
487 if (!ADS_ERR_OK(status
)) {
488 d_printf("ads_group_add: %s\n", ads_errstr(status
));
492 if (ads_count_replies(ads
, res
)) {
493 d_printf("ads_group_add: Group %s already exists\n", argv
[0]);
494 ads_msgfree(ads
, res
);
498 status
= ads_add_group_acct(ads
, argv
[0], opt_container
, opt_comment
);
500 if (ADS_ERR_OK(status
)) {
501 d_printf("Group %s added\n", argv
[0]);
504 d_printf("Could not add group %s: %s\n", argv
[0],
510 ads_msgfree(ads
, res
);
515 static int ads_group_delete(int argc
, const char **argv
)
523 return net_ads_group_usage(argc
, argv
);
526 if (!(ads
= ads_startup())) {
530 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
531 if (!ADS_ERR_OK(rc
)) {
532 DEBUG(0, ("Group %s does not exist\n", argv
[0]));
536 groupdn
= ads_get_dn(ads
, res
);
537 ads_msgfree(ads
, res
);
538 rc
= ads_del_dn(ads
, groupdn
);
539 ads_memfree(ads
, groupdn
);
540 if (!ADS_ERR_OK(rc
)) {
541 d_printf("Group %s deleted\n", argv
[0]);
545 d_printf("Error deleting group %s: %s\n", argv
[0],
551 int net_ads_group(int argc
, const char **argv
)
553 struct functable func
[] = {
554 {"ADD", ads_group_add
},
555 {"DELETE", ads_group_delete
},
560 const char *shortattrs
[] = {"sAMAccountName", NULL
};
561 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
562 char *disp_fields
[2] = {NULL
, NULL
};
565 if (!(ads
= ads_startup())) {
569 if (opt_long_list_entries
)
570 d_printf("\nGroup name Comment"\
571 "\n-----------------------------\n");
572 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
574 "(objectclass=group)",
575 opt_long_list_entries
? longattrs
:
576 shortattrs
, usergrp_display
,
582 return net_run_function(argc
, argv
, func
, net_ads_group_usage
);
585 static int net_ads_status(int argc
, const char **argv
)
591 if (!(ads
= ads_startup())) {
595 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
596 if (!ADS_ERR_OK(rc
)) {
597 d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc
));
602 if (ads_count_replies(ads
, res
) == 0) {
603 d_printf("No machine account for '%s' found\n", global_myname());
613 static int net_ads_leave(int argc
, const char **argv
)
615 ADS_STRUCT
*ads
= NULL
;
618 if (!secrets_init()) {
619 DEBUG(1,("Failed to initialise secrets database\n"));
624 net_use_machine_password();
627 if (!(ads
= ads_startup())) {
631 rc
= ads_leave_realm(ads
, global_myname());
632 if (!ADS_ERR_OK(rc
)) {
633 d_printf("Failed to delete host '%s' from the '%s' realm.\n",
634 global_myname(), ads
->config
.realm
);
639 d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads
->config
.realm
);
644 static int net_ads_join_ok(void)
646 ADS_STRUCT
*ads
= NULL
;
648 if (!secrets_init()) {
649 DEBUG(1,("Failed to initialise secrets database\n"));
653 net_use_machine_password();
655 if (!(ads
= ads_startup())) {
664 check that an existing join is OK
666 int net_ads_testjoin(int argc
, const char **argv
)
668 use_in_memory_ccache();
670 /* Display success or failure */
671 if (net_ads_join_ok() != 0) {
672 fprintf(stderr
,"Join to domain is not valid\n");
676 printf("Join is OK\n");
681 join a domain using ADS
683 int net_ads_join(int argc
, const char **argv
)
688 char *machine_account
= NULL
;
690 const char *org_unit
= "Computers";
695 uint32 sec_channel_type
= SEC_CHAN_WKSTA
;
696 uint32 account_type
= UF_WORKSTATION_TRUST_ACCOUNT
;
697 const char *short_domain_name
= NULL
;
698 TALLOC_CTX
*ctx
= NULL
;
704 if (!secrets_init()) {
705 DEBUG(1,("Failed to initialise secrets database\n"));
709 tmp_password
= generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
710 password
= strdup(tmp_password
);
712 if (!(ads
= ads_startup())) {
717 d_printf("realm must be set in in smb.conf for ADS join to succeed.\n");
722 if (strcmp(ads
->config
.realm
, lp_realm()) != 0) {
723 d_printf("realm of remote server (%s) and realm in smb.conf (%s) DO NOT match. Aborting join\n", ads
->config
.realm
, lp_realm());
728 ou_str
= ads_ou_string(org_unit
);
729 asprintf(&dn
, "%s,%s", ou_str
, ads
->config
.bind_path
);
732 rc
= ads_search_dn(ads
, &res
, dn
, NULL
);
733 ads_msgfree(ads
, res
);
735 if (rc
.error_type
== ENUM_ADS_ERROR_LDAP
&& rc
.err
.rc
== LDAP_NO_SUCH_OBJECT
) {
736 d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
743 if (!ADS_ERR_OK(rc
)) {
744 d_printf("ads_join_realm: %s\n", ads_errstr(rc
));
749 rc
= ads_join_realm(ads
, global_myname(), account_type
, org_unit
);
750 if (!ADS_ERR_OK(rc
)) {
751 d_printf("ads_join_realm: %s\n", ads_errstr(rc
));
756 rc
= ads_domain_sid(ads
, &dom_sid
);
757 if (!ADS_ERR_OK(rc
)) {
758 d_printf("ads_domain_sid: %s\n", ads_errstr(rc
));
763 if (asprintf(&machine_account
, "%s$", global_myname()) == -1) {
764 d_printf("asprintf failed\n");
769 rc
= ads_set_machine_password(ads
, machine_account
, password
);
770 if (!ADS_ERR_OK(rc
)) {
771 d_printf("ads_set_machine_password: %s\n", ads_errstr(rc
));
776 /* make sure we get the right workgroup */
778 if ( !(ctx
= talloc_init("net ads join")) ) {
779 d_printf("talloc_init() failed!\n");
784 rc
= ads_workgroup_name(ads
, ctx
, &short_domain_name
);
785 if ( ADS_ERR_OK(rc
) ) {
786 if ( !strequal(lp_workgroup(), short_domain_name
) ) {
787 d_printf("The workgroup in smb.conf does not match the short\n");
788 d_printf("domain name obtained from the server.\n");
789 d_printf("Using the name [%s] from the server.\n", short_domain_name
);
790 d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name
);
793 short_domain_name
= lp_workgroup();
796 d_printf("Using short domain name -- %s\n", short_domain_name
);
798 /* HACK ALRET! Store the sid and password under bother the lp_workgroup()
799 value from smb.conf and the string returned from the server. The former is
800 neede to bootstrap winbindd's first connection to the DC to get the real
801 short domain name --jerry */
803 if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid
)) {
804 DEBUG(1,("Failed to save domain sid\n"));
809 if (!secrets_store_machine_password(password
, lp_workgroup(), sec_channel_type
)) {
810 DEBUG(1,("Failed to save machine password\n"));
815 if (!secrets_store_domain_sid(short_domain_name
, &dom_sid
)) {
816 DEBUG(1,("Failed to save domain sid\n"));
821 if (!secrets_store_machine_password(password
, short_domain_name
, sec_channel_type
)) {
822 DEBUG(1,("Failed to save machine password\n"));
827 /* Now build the keytab, using the same ADS connection */
828 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads
)) {
829 DEBUG(1,("Error creating host keytab!\n"));
832 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads
->config
.realm
);
835 SAFE_FREE(machine_account
);
843 int net_ads_printer_usage(int argc
, const char **argv
)
846 "\nnet ads printer search <printer>"
847 "\n\tsearch for a printer in the directory"
848 "\nnet ads printer info <printer> <server>"
849 "\n\tlookup info in directory for printer on server"
850 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
851 "\nnet ads printer publish <printername>"
852 "\n\tpublish printer in directory"
853 "\n\t(note: printer name is required)\n"
854 "\nnet ads printer remove <printername>"
855 "\n\tremove printer from directory"
856 "\n\t(note: printer name is required)\n");
860 static int net_ads_printer_search(int argc
, const char **argv
)
866 if (!(ads
= ads_startup())) {
870 rc
= ads_find_printers(ads
, &res
);
872 if (!ADS_ERR_OK(rc
)) {
873 d_printf("ads_find_printer: %s\n", ads_errstr(rc
));
874 ads_msgfree(ads
, res
);
879 if (ads_count_replies(ads
, res
) == 0) {
880 d_printf("No results found\n");
881 ads_msgfree(ads
, res
);
887 ads_msgfree(ads
, res
);
892 static int net_ads_printer_info(int argc
, const char **argv
)
896 const char *servername
, *printername
;
899 if (!(ads
= ads_startup())) {
904 printername
= argv
[0];
910 servername
= argv
[1];
912 servername
= global_myname();
915 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
917 if (!ADS_ERR_OK(rc
)) {
918 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc
));
919 ads_msgfree(ads
, res
);
924 if (ads_count_replies(ads
, res
) == 0) {
925 d_printf("Printer '%s' not found\n", printername
);
926 ads_msgfree(ads
, res
);
932 ads_msgfree(ads
, res
);
938 void do_drv_upgrade_printer(int msg_type
, pid_t src
, void *buf
, size_t len
)
943 static int net_ads_printer_publish(int argc
, const char **argv
)
947 const char *servername
, *printername
;
948 struct cli_state
*cli
;
949 struct in_addr server_ip
;
951 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
952 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
953 char *prt_dn
, *srv_dn
, **srv_cn
;
956 if (!(ads
= ads_startup())) {
961 return net_ads_printer_usage(argc
, argv
);
964 printername
= argv
[0];
967 servername
= argv
[1];
969 servername
= global_myname();
972 /* Get printer data from SPOOLSS */
974 resolve_name(servername
, &server_ip
, 0x20);
976 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
979 opt_user_name
, opt_workgroup
,
980 opt_password
? opt_password
: "",
981 CLI_FULL_CONNECTION_USE_KERBEROS
,
984 if (NT_STATUS_IS_ERR(nt_status
)) {
985 d_printf("Unable to open a connnection to %s to obtain data "
986 "for %s\n", servername
, printername
);
991 /* Publish on AD server */
993 ads_find_machine_acct(ads
, &res
, servername
);
995 if (ads_count_replies(ads
, res
) == 0) {
996 d_printf("Could not find machine account for server %s\n",
1002 srv_dn
= ldap_get_dn(ads
->ld
, res
);
1003 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1005 asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn
[0], printername
, srv_dn
);
1007 cli_nt_session_open(cli
, PI_SPOOLSS
);
1008 get_remote_printer_publishing_data(cli
, mem_ctx
, &mods
, printername
);
1010 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1011 if (!ADS_ERR_OK(rc
)) {
1012 d_printf("ads_publish_printer: %s\n", ads_errstr(rc
));
1017 d_printf("published printer\n");
1023 static int net_ads_printer_remove(int argc
, const char **argv
)
1027 const char *servername
;
1031 if (!(ads
= ads_startup())) {
1036 return net_ads_printer_usage(argc
, argv
);
1040 servername
= argv
[1];
1042 servername
= global_myname();
1045 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1047 if (!ADS_ERR_OK(rc
)) {
1048 d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc
));
1049 ads_msgfree(ads
, res
);
1054 if (ads_count_replies(ads
, res
) == 0) {
1055 d_printf("Printer '%s' not found\n", argv
[1]);
1056 ads_msgfree(ads
, res
);
1061 prt_dn
= ads_get_dn(ads
, res
);
1062 ads_msgfree(ads
, res
);
1063 rc
= ads_del_dn(ads
, prt_dn
);
1064 ads_memfree(ads
, prt_dn
);
1066 if (!ADS_ERR_OK(rc
)) {
1067 d_printf("ads_del_dn: %s\n", ads_errstr(rc
));
1076 static int net_ads_printer(int argc
, const char **argv
)
1078 struct functable func
[] = {
1079 {"SEARCH", net_ads_printer_search
},
1080 {"INFO", net_ads_printer_info
},
1081 {"PUBLISH", net_ads_printer_publish
},
1082 {"REMOVE", net_ads_printer_remove
},
1086 return net_run_function(argc
, argv
, func
, net_ads_printer_usage
);
1090 static int net_ads_password(int argc
, const char **argv
)
1093 const char *auth_principal
= opt_user_name
;
1094 const char *auth_password
= opt_password
;
1096 char *new_password
= NULL
;
1101 if (opt_user_name
== NULL
|| opt_password
== NULL
) {
1102 d_printf("You must supply an administrator username/password\n");
1107 d_printf("ERROR: You must say which username to change password for\n");
1112 if (!strchr_m(user
, '@')) {
1113 asprintf(&c
, "%s@%s", argv
[0], lp_realm());
1117 use_in_memory_ccache();
1118 c
= strchr(auth_principal
, '@');
1125 /* use the realm so we can eventually change passwords for users
1126 in realms other than default */
1127 if (!(ads
= ads_init(realm
, NULL
, NULL
))) {
1131 /* we don't actually need a full connect, but it's the easy way to
1132 fill in the KDC's addresss */
1135 if (!ads
|| !ads
->config
.realm
) {
1136 d_printf("Didn't find the kerberos server!\n");
1141 new_password
= (char *)argv
[1];
1143 asprintf(&prompt
, "Enter new password for %s:", user
);
1144 new_password
= getpass(prompt
);
1148 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
1149 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
1150 if (!ADS_ERR_OK(ret
)) {
1151 d_printf("Password change failed :-( ...\n");
1156 d_printf("Password change for %s completed.\n", user
);
1162 int net_ads_changetrustpw(int argc
, const char **argv
)
1165 char *host_principal
;
1169 if (!secrets_init()) {
1170 DEBUG(1,("Failed to initialise secrets database\n"));
1174 net_use_machine_password();
1176 use_in_memory_ccache();
1178 if (!(ads
= ads_startup())) {
1182 fstrcpy(my_name
, global_myname());
1183 strlower_m(my_name
);
1184 asprintf(&host_principal
, "%s@%s", my_name
, ads
->config
.realm
);
1185 d_printf("Changing password for principal: HOST/%s\n", host_principal
);
1187 ret
= ads_change_trust_account_password(ads
, host_principal
);
1189 if (!ADS_ERR_OK(ret
)) {
1190 d_printf("Password change failed :-( ...\n");
1192 SAFE_FREE(host_principal
);
1196 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal
);
1198 if (lp_use_kerberos_keytab()) {
1199 d_printf("Attempting to update system keytab with new password.\n");
1200 if (ads_keytab_create_default(ads
)) {
1201 d_printf("Failed to update system keytab.\n");
1206 SAFE_FREE(host_principal
);
1212 help for net ads search
1214 static int net_ads_search_usage(int argc
, const char **argv
)
1217 "\nnet ads search <expression> <attributes...>\n"\
1218 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1219 "The expression is a standard LDAP search expression, and the\n"\
1220 "attributes are a list of LDAP fields to show in the results\n\n"\
1221 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1223 net_common_flags_usage(argc
, argv
);
1229 general ADS search function. Useful in diagnosing problems in ADS
1231 static int net_ads_search(int argc
, const char **argv
)
1235 const char *ldap_exp
;
1240 return net_ads_search_usage(argc
, argv
);
1243 if (!(ads
= ads_startup())) {
1250 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
1252 ldap_exp
, attrs
, &res
);
1253 if (!ADS_ERR_OK(rc
)) {
1254 d_printf("search failed: %s\n", ads_errstr(rc
));
1259 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
1261 /* dump the results */
1264 ads_msgfree(ads
, res
);
1272 help for net ads search
1274 static int net_ads_dn_usage(int argc
, const char **argv
)
1277 "\nnet ads dn <dn> <attributes...>\n"\
1278 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1279 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1280 "to show in the results\n\n"\
1281 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' 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_dn(int argc
, const char **argv
)
1300 return net_ads_dn_usage(argc
, argv
);
1303 if (!(ads
= ads_startup())) {
1310 rc
= ads_do_search_all(ads
, dn
,
1312 "(objectclass=*)", attrs
, &res
);
1313 if (!ADS_ERR_OK(rc
)) {
1314 d_printf("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
);
1330 static int net_ads_keytab_usage(int argc
, const char **argv
)
1333 "net ads keytab <COMMAND>\n"\
1334 "<COMMAND> can be either:\n"\
1335 " CREATE Creates a fresh keytab\n"\
1336 " ADD Adds new service principal\n"\
1337 " FLUSH Flushes out all keytab entries\n"\
1338 " HELP Prints this help message\n"\
1339 "The ADD command will take arguments, the other commands\n"\
1340 "will not take any arguments. The arguments given to ADD\n"\
1341 "should be a list of principals to add. For example, \n"\
1342 " net ads keytab add srv1 srv2\n"\
1343 "will add principals for the services srv1 and srv2 to the\n"\
1344 "system's keytab.\n"\
1350 static int net_ads_keytab_flush(int argc
, const char **argv
)
1355 if (!(ads
= ads_startup())) {
1358 ret
= ads_keytab_flush(ads
);
1363 static int net_ads_keytab_add(int argc
, const char **argv
)
1369 d_printf("Processing principals to add...\n");
1370 if (!(ads
= ads_startup())) {
1373 for (i
= 0; i
< argc
; i
++) {
1374 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
1380 static int net_ads_keytab_create(int argc
, const char **argv
)
1385 if (!(ads
= ads_startup())) {
1388 ret
= ads_keytab_create_default(ads
);
1393 int net_ads_keytab(int argc
, const char **argv
)
1395 struct functable func
[] = {
1396 {"CREATE", net_ads_keytab_create
},
1397 {"ADD", net_ads_keytab_add
},
1398 {"FLUSH", net_ads_keytab_flush
},
1399 {"HELP", net_ads_keytab_usage
},
1403 if (!lp_use_kerberos_keytab()) {
1404 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
1405 use keytab functions.\n");
1408 return net_run_function(argc
, argv
, func
, net_ads_keytab_usage
);
1411 int net_ads_help(int argc
, const char **argv
)
1413 struct functable func
[] = {
1414 {"USER", net_ads_user_usage
},
1415 {"GROUP", net_ads_group_usage
},
1416 {"PRINTER", net_ads_printer_usage
},
1417 {"SEARCH", net_ads_search_usage
},
1419 {"INFO", net_ads_info
},
1420 {"JOIN", net_ads_join
},
1421 {"LEAVE", net_ads_leave
},
1422 {"STATUS", net_ads_status
},
1423 {"PASSWORD", net_ads_password
},
1424 {"CHANGETRUSTPW", net_ads_changetrustpw
},
1429 return net_run_function(argc
, argv
, func
, net_ads_usage
);
1432 int net_ads(int argc
, const char **argv
)
1434 struct functable func
[] = {
1435 {"INFO", net_ads_info
},
1436 {"JOIN", net_ads_join
},
1437 {"TESTJOIN", net_ads_testjoin
},
1438 {"LEAVE", net_ads_leave
},
1439 {"STATUS", net_ads_status
},
1440 {"USER", net_ads_user
},
1441 {"GROUP", net_ads_group
},
1442 {"PASSWORD", net_ads_password
},
1443 {"CHANGETRUSTPW", net_ads_changetrustpw
},
1444 {"PRINTER", net_ads_printer
},
1445 {"SEARCH", net_ads_search
},
1447 {"WORKGROUP", net_ads_workgroup
},
1448 {"LOOKUP", net_ads_lookup
},
1449 {"KEYTAB", net_ads_keytab
},
1450 {"HELP", net_ads_help
},
1454 return net_run_function(argc
, argv
, func
, net_ads_usage
);
1459 static int net_ads_noads(void)
1461 d_printf("ADS support not compiled in\n");
1465 int net_ads_keytab(int argc
, const char **argv
)
1467 return net_ads_noads();
1470 int net_ads_usage(int argc
, const char **argv
)
1472 return net_ads_noads();
1475 int net_ads_help(int argc
, const char **argv
)
1477 return net_ads_noads();
1480 int net_ads_changetrustpw(int argc
, const char **argv
)
1482 return net_ads_noads();
1485 int net_ads_join(int argc
, const char **argv
)
1487 return net_ads_noads();
1490 int net_ads_user(int argc
, const char **argv
)
1492 return net_ads_noads();
1495 int net_ads_group(int argc
, const char **argv
)
1497 return net_ads_noads();
1500 /* this one shouldn't display a message */
1501 int net_ads_check(void)
1506 int net_ads(int argc
, const char **argv
)
1508 return net_ads_usage(argc
, argv
);