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)
7 Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "utils/net.h"
27 /* Macro for checking RPC error codes to make things more readable */
29 #define CHECK_RPC_ERR(rpc, msg) \
30 if (!NT_STATUS_IS_OK(result = rpc)) { \
31 DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
35 #define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
36 if (!NT_STATUS_IS_OK(result = rpc)) { \
37 DEBUG(0, debug_args); \
43 int net_ads_usage(int argc, const char **argv)
46 "\nnet ads join <org_unit>"\
47 "\n\tjoins the local machine to a ADS realm\n"\
49 "\n\tremoves the local machine from a ADS realm\n"\
51 "\n\ttests that an exiting join is OK\n"\
53 "\n\tlist, add, or delete users in the realm\n"\
55 "\n\tlist, add, or delete groups in the realm\n"\
57 "\n\tshows some info on the server\n"\
59 "\n\tdump the machine account details to stdout\n"
61 "\n\tperform a CLDAP search on the server\n"
62 "\nnet ads password <username@realm> <password> -Uadmin_username@realm%%admin_pass"\
63 "\n\tchange a user's password using an admin account"\
64 "\n\t(note: use realm in UPPERCASE, prompts if password is obmitted)\n"\
65 "\nnet ads changetrustpw"\
66 "\n\tchange the trust account password of this machine in the AD tree\n"\
67 "\nnet ads printer [info | publish | remove] <printername> <servername>"\
68 "\n\t lookup, add, or remove directory entry for a printer\n"\
70 "\n\tperform a raw LDAP search and dump the results\n"
72 "\n\tperform a raw LDAP search and dump attributes of a particular DN\n"
74 "\n\tperform a raw LDAP search and dump attributes of a particular SID\n"
76 "\n\tcreates and updates the kerberos system keytab file\n"
83 do a cldap netlogon query
85 static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
87 struct cldap_netlogon_reply reply;
89 if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap_ip), ads->server.realm, &reply ) ) {
90 d_fprintf(stderr, "CLDAP query failed!\n");
94 d_printf("Information for Domain Controller: %s\n\n",
95 inet_ntoa(ads->ldap_ip));
97 d_printf("Response Type: ");
99 case SAMLOGON_AD_UNK_R:
100 d_printf("SAMLOGON\n");
103 d_printf("SAMLOGON_USER\n");
106 d_printf("0x%x\n", reply.type);
109 d_printf("GUID: %s\n",
110 smb_uuid_string_static(smb_uuid_unpack_static(reply.guid)));
113 "\tIs a GC of the forest: %s\n"
114 "\tIs an LDAP server: %s\n"
115 "\tSupports DS: %s\n"
116 "\tIs running a KDC: %s\n"
117 "\tIs running time services: %s\n"
118 "\tIs the closest DC: %s\n"
119 "\tIs writable: %s\n"
120 "\tHas a hardware clock: %s\n"
121 "\tIs a non-domain NC serviced by LDAP server: %s\n",
122 (reply.flags & ADS_PDC) ? "yes" : "no",
123 (reply.flags & ADS_GC) ? "yes" : "no",
124 (reply.flags & ADS_LDAP) ? "yes" : "no",
125 (reply.flags & ADS_DS) ? "yes" : "no",
126 (reply.flags & ADS_KDC) ? "yes" : "no",
127 (reply.flags & ADS_TIMESERV) ? "yes" : "no",
128 (reply.flags & ADS_CLOSEST) ? "yes" : "no",
129 (reply.flags & ADS_WRITABLE) ? "yes" : "no",
130 (reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
131 (reply.flags & ADS_NDNC) ? "yes" : "no");
133 printf("Forest:\t\t\t%s\n", reply.forest);
134 printf("Domain:\t\t\t%s\n", reply.domain);
135 printf("Domain Controller:\t%s\n", reply.hostname);
137 printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
138 printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
140 if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
141 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
143 printf("Site Name:\t\t%s\n", reply.site_name);
144 printf("Site Name (2):\t\t%s\n", reply.site_name_2);
146 d_printf("NT Version: %d\n", reply.version);
147 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
148 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
155 this implements the CLDAP based netlogon lookup requests
156 for finding the domain controller of a ADS domain
158 static int net_ads_lookup(int argc, const char **argv)
162 const char *realm = NULL;
164 if ( strequal(lp_workgroup(), opt_target_workgroup ) )
167 ads = ads_init(realm, opt_target_workgroup, opt_host);
169 ads->auth.flags |= ADS_AUTH_NO_BIND;
172 status = ads_connect(ads);
173 if (!ADS_ERR_OK(status) || !ads) {
174 d_fprintf(stderr, "Didn't find the cldap server!\n");
178 if (!ads->config.realm) {
179 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
180 ads->ldap_port = 389;
183 return net_ads_cldap_netlogon(ads);
188 static int net_ads_info(int argc, const char **argv)
192 if ( (ads = ads_init(lp_realm(), opt_target_workgroup, opt_host)) != NULL ) {
193 ads->auth.flags |= ADS_AUTH_NO_BIND;
198 if (!ads || !ads->config.realm) {
199 d_fprintf(stderr, "Didn't find the ldap server!\n");
203 /* Try to set the server's current time since we didn't do a full
204 TCP LDAP session initially */
206 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
207 d_fprintf( stderr, "Failed to get server's current time!\n");
210 d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
211 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
212 d_printf("Realm: %s\n", ads->config.realm);
213 d_printf("Bind Path: %s\n", ads->config.bind_path);
214 d_printf("LDAP port: %d\n", ads->ldap_port);
215 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
217 d_printf("KDC server: %s\n", ads->auth.kdc_server );
218 d_printf("Server time offset: %d\n", ads->auth.time_offset );
223 static void use_in_memory_ccache(void) {
224 /* Use in-memory credentials cache so we do not interfere with
225 * existing credentials */
226 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
229 static ADS_STRUCT *ads_startup(void)
233 BOOL need_password = False;
234 BOOL second_time = False;
237 /* lp_realm() should be handled by a command line param,
238 However, the join requires that realm be set in smb.conf
239 and compares our realm with the remote server's so this is
240 ok until someone needs more flexibility */
242 ads = ads_init(lp_realm(), opt_target_workgroup, opt_host);
244 if (!opt_user_name) {
245 opt_user_name = "administrator";
248 if (opt_user_specified) {
249 need_password = True;
253 if (!opt_password && need_password && !opt_machine_pass) {
255 asprintf(&prompt,"%s's password: ", opt_user_name);
256 opt_password = getpass(prompt);
261 use_in_memory_ccache();
262 ads->auth.password = smb_xstrdup(opt_password);
265 ads->auth.user_name = smb_xstrdup(opt_user_name);
268 * If the username is of the form "name@realm",
269 * extract the realm and convert to upper case.
270 * This is only used to establish the connection.
272 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
274 ads->auth.realm = smb_xstrdup(cp);
275 strupper_m(ads->auth.realm);
278 status = ads_connect(ads);
280 if (!ADS_ERR_OK(status)) {
281 if (!need_password && !second_time) {
282 need_password = True;
286 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
295 Check to see if connection can be made via ads.
296 ads_startup() stores the password in opt_password if it needs to so
297 that rpc or rap can use it without re-prompting.
299 int net_ads_check(void)
304 if ( (ads = ads_init( lp_realm(), lp_workgroup(), NULL )) == NULL ) {
308 ads->auth.flags |= ADS_AUTH_NO_BIND;
310 status = ads_connect(ads);
311 if ( !ADS_ERR_OK(status) ) {
320 determine the netbios workgroup name for a domain
322 static int net_ads_workgroup(int argc, const char **argv)
326 const char *realm = NULL;
327 struct cldap_netlogon_reply reply;
329 if ( strequal(lp_workgroup(), opt_target_workgroup ) )
332 ads = ads_init(realm, opt_target_workgroup, opt_host);
334 ads->auth.flags |= ADS_AUTH_NO_BIND;
337 status = ads_connect(ads);
338 if (!ADS_ERR_OK(status) || !ads) {
339 d_fprintf(stderr, "Didn't find the cldap server!\n");
343 if (!ads->config.realm) {
344 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
345 ads->ldap_port = 389;
348 if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap_ip), ads->server.realm, &reply ) ) {
349 d_fprintf(stderr, "CLDAP query failed!\n");
353 d_printf("Workgroup: %s\n", reply.netbios_domain);
362 static BOOL usergrp_display(char *field, void **values, void *data_area)
364 char **disp_fields = (char **) data_area;
366 if (!field) { /* must be end of record */
367 if (disp_fields[0]) {
368 if (!strchr_m(disp_fields[0], '$')) {
370 d_printf("%-21.21s %s\n",
371 disp_fields[0], disp_fields[1]);
373 d_printf("%s\n", disp_fields[0]);
376 SAFE_FREE(disp_fields[0]);
377 SAFE_FREE(disp_fields[1]);
380 if (!values) /* must be new field, indicate string field */
382 if (StrCaseCmp(field, "sAMAccountName") == 0) {
383 disp_fields[0] = SMB_STRDUP((char *) values[0]);
385 if (StrCaseCmp(field, "description") == 0)
386 disp_fields[1] = SMB_STRDUP((char *) values[0]);
390 static int net_ads_user_usage(int argc, const char **argv)
392 return net_help_user(argc, argv);
395 static int ads_user_add(int argc, const char **argv)
403 if (argc < 1) return net_ads_user_usage(argc, argv);
405 if (!(ads = ads_startup())) {
409 status = ads_find_user_acct(ads, &res, argv[0]);
411 if (!ADS_ERR_OK(status)) {
412 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
416 if (ads_count_replies(ads, res)) {
417 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
421 if (opt_container == NULL) {
422 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
425 status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
427 if (!ADS_ERR_OK(status)) {
428 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
433 /* if no password is to be set, we're done */
435 d_printf("User %s added\n", argv[0]);
440 /* try setting the password */
441 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
442 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
443 ads->auth.time_offset);
445 if (ADS_ERR_OK(status)) {
446 d_printf("User %s added\n", argv[0]);
451 /* password didn't set, delete account */
452 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
453 argv[0], ads_errstr(status));
454 ads_msgfree(ads, res);
455 status=ads_find_user_acct(ads, &res, argv[0]);
456 if (ADS_ERR_OK(status)) {
457 userdn = ads_get_dn(ads, res);
458 ads_del_dn(ads, userdn);
459 ads_memfree(ads, userdn);
464 ads_msgfree(ads, res);
469 static int ads_user_info(int argc, const char **argv)
474 const char *attrs[] = {"memberOf", NULL};
475 char *searchstring=NULL;
480 return net_ads_user_usage(argc, argv);
483 escaped_user = escape_ldap_string_alloc(argv[0]);
486 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
490 if (!(ads = ads_startup())) {
491 SAFE_FREE(escaped_user);
495 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
496 rc = ads_search(ads, &res, searchstring, attrs);
497 safe_free(searchstring);
499 if (!ADS_ERR_OK(rc)) {
500 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
502 SAFE_FREE(escaped_user);
506 grouplist = ldap_get_values(ads->ld, res, "memberOf");
511 for (i=0;grouplist[i];i++) {
512 groupname = ldap_explode_dn(grouplist[i], 1);
513 d_printf("%s\n", groupname[0]);
514 ldap_value_free(groupname);
516 ldap_value_free(grouplist);
519 ads_msgfree(ads, res);
521 SAFE_FREE(escaped_user);
525 static int ads_user_delete(int argc, const char **argv)
533 return net_ads_user_usage(argc, argv);
536 if (!(ads = ads_startup())) {
540 rc = ads_find_user_acct(ads, &res, argv[0]);
541 if (!ADS_ERR_OK(rc)) {
542 DEBUG(0, ("User %s does not exist\n", argv[0]));
546 userdn = ads_get_dn(ads, res);
547 ads_msgfree(ads, res);
548 rc = ads_del_dn(ads, userdn);
549 ads_memfree(ads, userdn);
550 if (!ADS_ERR_OK(rc)) {
551 d_printf("User %s deleted\n", argv[0]);
555 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
561 int net_ads_user(int argc, const char **argv)
563 struct functable func[] = {
564 {"ADD", ads_user_add},
565 {"INFO", ads_user_info},
566 {"DELETE", ads_user_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("\nUser name Comment"\
582 "\n-----------------------------\n");
584 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
586 "(objectCategory=user)",
587 opt_long_list_entries ? longattrs :
588 shortattrs, usergrp_display,
594 return net_run_function(argc, argv, func, net_ads_user_usage);
597 static int net_ads_group_usage(int argc, const char **argv)
599 return net_help_group(argc, argv);
602 static int ads_group_add(int argc, const char **argv)
610 return net_ads_group_usage(argc, argv);
613 if (!(ads = ads_startup())) {
617 status = ads_find_user_acct(ads, &res, argv[0]);
619 if (!ADS_ERR_OK(status)) {
620 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
624 if (ads_count_replies(ads, res)) {
625 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
626 ads_msgfree(ads, res);
630 if (opt_container == NULL) {
631 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
634 status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
636 if (ADS_ERR_OK(status)) {
637 d_printf("Group %s added\n", argv[0]);
640 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
646 ads_msgfree(ads, res);
651 static int ads_group_delete(int argc, const char **argv)
659 return net_ads_group_usage(argc, argv);
662 if (!(ads = ads_startup())) {
666 rc = ads_find_user_acct(ads, &res, argv[0]);
667 if (!ADS_ERR_OK(rc)) {
668 DEBUG(0, ("Group %s does not exist\n", argv[0]));
672 groupdn = ads_get_dn(ads, res);
673 ads_msgfree(ads, res);
674 rc = ads_del_dn(ads, groupdn);
675 ads_memfree(ads, groupdn);
676 if (!ADS_ERR_OK(rc)) {
677 d_printf("Group %s deleted\n", argv[0]);
681 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
687 int net_ads_group(int argc, const char **argv)
689 struct functable func[] = {
690 {"ADD", ads_group_add},
691 {"DELETE", ads_group_delete},
696 const char *shortattrs[] = {"sAMAccountName", NULL};
697 const char *longattrs[] = {"sAMAccountName", "description", NULL};
698 char *disp_fields[2] = {NULL, NULL};
701 if (!(ads = ads_startup())) {
705 if (opt_long_list_entries)
706 d_printf("\nGroup name Comment"\
707 "\n-----------------------------\n");
708 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
710 "(objectCategory=group)",
711 opt_long_list_entries ? longattrs :
712 shortattrs, usergrp_display,
718 return net_run_function(argc, argv, func, net_ads_group_usage);
721 static int net_ads_status(int argc, const char **argv)
727 if (!(ads = ads_startup())) {
731 rc = ads_find_machine_acct(ads, &res, global_myname());
732 if (!ADS_ERR_OK(rc)) {
733 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
738 if (ads_count_replies(ads, res) == 0) {
739 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
749 static int net_ads_leave(int argc, const char **argv)
751 ADS_STRUCT *ads = NULL;
754 if (!secrets_init()) {
755 DEBUG(1,("Failed to initialise secrets database\n"));
760 net_use_machine_password();
763 if (!(ads = ads_startup())) {
767 rc = ads_leave_realm(ads, global_myname());
768 if (!ADS_ERR_OK(rc)) {
769 d_fprintf(stderr, "Failed to delete host '%s' from the '%s' realm.\n",
770 global_myname(), ads->config.realm);
775 d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
780 static int net_ads_join_ok(void)
782 ADS_STRUCT *ads = NULL;
784 if (!secrets_init()) {
785 DEBUG(1,("Failed to initialise secrets database\n"));
789 net_use_machine_password();
791 if (!(ads = ads_startup())) {
800 check that an existing join is OK
802 int net_ads_testjoin(int argc, const char **argv)
804 use_in_memory_ccache();
806 /* Display success or failure */
807 if (net_ads_join_ok() != 0) {
808 fprintf(stderr,"Join to domain is not valid\n");
812 printf("Join is OK\n");
816 /*******************************************************************
817 Simple configu checks before beginning the join
818 ********************************************************************/
820 static int check_ads_config( void )
822 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
823 d_printf("Host is not configured as a member server.\n");
827 if (strlen(global_myname()) > 15) {
828 d_printf("Our netbios name can be at most 15 chars long, "
829 "\"%s\" is %d chars long\n",
830 global_myname(), strlen(global_myname()));
834 if ( lp_security() == SEC_ADS && !*lp_realm()) {
835 d_fprintf(stderr, "realm must be set in in smb.conf for ADS "
836 "join to succeed.\n");
840 if (!secrets_init()) {
841 DEBUG(1,("Failed to initialise secrets database\n"));
848 /*******************************************************************
849 Store the machine password and domain SID
850 ********************************************************************/
852 static int store_domain_account( const char *domain, DOM_SID *sid, const char *pw )
854 if (!secrets_store_domain_sid(domain, sid)) {
855 DEBUG(1,("Failed to save domain sid\n"));
859 if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
860 DEBUG(1,("Failed to save machine password\n"));
867 /*******************************************************************
868 ********************************************************************/
870 static NTSTATUS join_fetch_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli, DOM_SID **sid )
872 struct rpc_pipe_client *pipe_hnd = NULL;
874 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
877 if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status)) == NULL ) {
878 DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
879 nt_errstr(status) ));
883 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
884 SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
885 if ( !NT_STATUS_IS_OK(status) )
888 status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx,
889 &lsa_pol, 5, &domain, sid);
890 if ( !NT_STATUS_IS_OK(status) )
893 rpccli_lsa_close(pipe_hnd, mem_ctx, &lsa_pol);
894 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
896 /* Bail out if domain didn't get set. */
898 DEBUG(0, ("Could not get domain name.\n"));
899 return NT_STATUS_UNSUCCESSFUL;
905 /*******************************************************************
907 ********************************************************************/
909 static NTSTATUS join_create_machine( TALLOC_CTX *mem_ctx, struct cli_state *cli,
910 DOM_SID *dom_sid, const char *clear_pw )
912 struct rpc_pipe_client *pipe_hnd = NULL;
913 POLICY_HND sam_pol, domain_pol, user_pol;
914 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
916 const char *const_acct_name;
918 uint32 num_rids, *name_types, *user_rids;
919 uint32 flags = 0x3e8;
920 uint32 acb_info = ACB_WSTRUST | ACB_PWNOEXP;
922 SAM_USERINFO_CTR ctr;
923 SAM_USER_INFO_24 p24;
924 SAM_USER_INFO_16 p16;
925 uchar md4_trust_password[16];
927 /* Open the domain */
929 if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
930 DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
931 nt_errstr(status) ));
935 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
936 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
937 if ( !NT_STATUS_IS_OK(status) )
941 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
942 SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
943 if ( !NT_STATUS_IS_OK(status) )
946 /* Create domain user */
948 acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
949 strlower_m(acct_name);
950 const_acct_name = acct_name;
952 #ifndef ENCTYPE_ARCFOUR_HMAC
953 acb_info |= ACB_USE_DES_KEY_ONLY;
956 status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
957 acct_name, acb_info, 0xe005000b, &user_pol, &user_rid);
959 if ( !NT_STATUS_IS_OK(status)
960 && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS))
962 d_fprintf(stderr, "Creation of workstation account failed\n");
964 /* If NT_STATUS_ACCESS_DENIED then we have a valid
965 username/password combo but the user does not have
966 administrator access. */
968 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
969 d_fprintf(stderr, "User specified does not have administrator privileges\n");
974 /* We *must* do this.... don't ask... */
976 if (NT_STATUS_IS_OK(status)) {
977 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
980 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
981 &domain_pol, flags, 1, &const_acct_name,
982 &num_rids, &user_rids, &name_types);
983 if ( !NT_STATUS_IS_OK(status) )
986 if ( name_types[0] != SID_NAME_USER) {
987 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
988 return NT_STATUS_INVALID_WORKSTATION;
991 user_rid = user_rids[0];
993 /* Open handle on user */
995 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
996 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
998 /* Create a random machine account password */
1000 E_md4hash( clear_pw, md4_trust_password);
1001 encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
1003 /* Set password on machine account */
1008 init_sam_user_info24(&p24, (char *)pwbuf,24);
1010 ctr.switch_value = 24;
1011 ctr.info.id24 = &p24;
1013 status = rpccli_samr_set_userinfo(pipe_hnd, mem_ctx, &user_pol,
1014 24, &cli->user_session_key, &ctr);
1016 /* Why do we have to try to (re-)set the ACB to be the same as what
1017 we passed in the samr_create_dom_user() call? When a NT
1018 workstation is joined to a domain by an administrator the
1019 acb_info is set to 0x80. For a normal user with "Add
1020 workstations to the domain" rights the acb_info is 0x84. I'm
1021 not sure whether it is supposed to make a difference or not. NT
1022 seems to cope with either value so don't bomb out if the set
1023 userinfo2 level 0x10 fails. -tpot */
1026 ctr.switch_value = 16;
1027 ctr.info.id16 = &p16;
1029 init_sam_user_info16(&p16, acb_info);
1031 /* Ignoring the return value is necessary for joining a domain
1032 as a normal user with "Add workstation to domain" privilege. */
1034 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
1035 &cli->user_session_key, &ctr);
1037 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
1038 cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
1043 /*******************************************************************
1045 ********************************************************************/
1047 static int net_join_domain( TALLOC_CTX *ctx, const char *servername,
1048 struct in_addr *ip, DOM_SID **dom_sid, const char *password )
1051 struct cli_state *cli = NULL;
1053 if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, ip, servername)) )
1056 saf_store( cli->server_domain, cli->desthost );
1058 if ( !NT_STATUS_IS_OK(join_fetch_domain_sid( ctx, cli, dom_sid )) )
1061 if ( !NT_STATUS_IS_OK(join_create_machine( ctx, cli, *dom_sid, password )) )
1073 /*******************************************************************
1074 Set a machines dNSHostName and servicePrincipalName attributes
1075 ********************************************************************/
1077 static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
1079 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1080 char *host_upn, *new_dn;
1082 const char *servicePrincipalName[3] = {NULL, NULL, NULL};
1085 LDAPMessage *res = NULL;
1086 char *dn_string = NULL;
1087 const char *machine_name = global_myname();
1090 if ( !machine_name ) {
1091 return ADS_ERROR(LDAP_NO_MEMORY);
1096 status = ads_find_machine_acct(ads_s, (void **)(void *)&res, machine_name);
1097 if (!ADS_ERR_OK(status))
1100 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1101 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1102 return ADS_ERROR(LDAP_NO_MEMORY);
1105 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1106 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1110 new_dn = talloc_strdup(ctx, dn_string);
1111 ads_memfree(ads_s, dn_string);
1113 return ADS_ERROR(LDAP_NO_MEMORY);
1116 /* Windows only creates HOST/shortname & HOST/fqdn. We create
1117 the UPN as well so that 'kinit -k' will work. You can only
1118 request a TGT for entries with a UPN in AD. */
1120 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) )
1123 servicePrincipalName[0] = psp;
1125 name_to_fqdn(my_fqdn, machine_name);
1126 strlower_m(my_fqdn);
1127 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) )
1129 servicePrincipalName[1] = psp;
1131 if (!(host_upn = talloc_asprintf(ctx, "%s@%s", servicePrincipalName[0], ads_s->config.realm)))
1134 /* now do the mods */
1136 if (!(mods = ads_init_mods(ctx))) {
1140 /* fields of primary importance */
1142 ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
1143 ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
1145 ads_mod_str(ctx, &mods, "userPrincipalName", host_upn);
1146 ads_mod_str(ctx, &mods, "operatingSystem", "Samba");
1147 ads_mod_str(ctx, &mods, "operatingSystemVersion", SAMBA_VERSION_STRING);
1150 status = ads_gen_mod(ads_s, new_dn, mods);
1153 ads_msgfree(ads_s, res);
1159 /*******************************************************************
1160 join a domain using ADS (LDAP mods)
1161 ********************************************************************/
1163 static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
1165 ADS_STRUCT *ads_s = ads;
1166 ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
1168 LDAPMessage *res = NULL;
1170 ou_str = ads_ou_string(ads, ou);
1171 asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
1175 ads_s = ads_init( ads->config.realm, NULL, ads->config.ldap_server_name );
1178 rc = ads_connect( ads_s );
1181 if ( !ADS_ERR_OK(rc) ) {
1186 rc = ads_search_dn(ads, (void**)&res, dn, NULL);
1187 ads_msgfree(ads, res);
1189 if (!ADS_ERR_OK(rc)) {
1193 /* Attempt to create the machine account and bail if this fails.
1194 Assume that the admin wants exactly what they requested */
1196 rc = ads_create_machine_acct( ads, global_myname(), dn );
1197 if ( rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS ) {
1201 if ( !ADS_ERR_OK(rc) ) {
1207 ads_destroy( &ads_s );
1213 /*******************************************************************
1214 join a domain using ADS (LDAP mods)
1215 ********************************************************************/
1217 int net_ads_join(int argc, const char **argv)
1219 ADS_STRUCT *ads, *ads_s;
1221 char *machine_account = NULL;
1222 const char *short_domain_name = NULL;
1223 char *tmp_password, *password;
1224 struct cldap_netlogon_reply cldap_reply;
1226 DOM_SID *domain_sid = NULL;
1228 if ( check_ads_config() != 0 ) {
1229 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1233 if ( (ads = ads_startup()) == NULL ) {
1237 if (strcmp(ads->config.realm, lp_realm()) != 0) {
1238 d_fprintf(stderr, "realm of remote server (%s) and realm in smb.conf "
1239 "(%s) DO NOT match. Aborting join\n", ads->config.realm,
1245 if (!(ctx = talloc_init("net_ads_join"))) {
1246 DEBUG(0, ("Could not initialise talloc context\n"));
1250 /* If we were given an OU, try to create the machine in the OU account
1251 first and then do the normal RPC join */
1254 status = net_precreate_machine_acct( ads, argv[0] );
1255 if ( !ADS_ERR_OK(status) ) {
1256 d_fprintf( stderr, "Failed to pre-create the machine object "
1257 "in OU %s.\n", argv[0]);
1258 ads_destroy( &ads );
1263 /* Do the domain join here */
1265 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1266 password = talloc_strdup(ctx, tmp_password);
1268 if ( net_join_domain( ctx, ads->config.ldap_server_name, &ads->ldap_ip, &domain_sid, password ) != 0 ) {
1269 d_fprintf(stderr, "Failed to join domain!\n");
1273 /* Check the short name of the domain */
1275 ZERO_STRUCT( cldap_reply );
1277 if ( ads_cldap_netlogon( ads->config.ldap_server_name,
1278 ads->server.realm, &cldap_reply ) )
1280 short_domain_name = talloc_strdup( ctx, cldap_reply.netbios_domain );
1281 if ( !strequal(lp_workgroup(), short_domain_name) ) {
1282 d_printf("The workgroup in smb.conf does not match the short\n");
1283 d_printf("domain name obtained from the server.\n");
1284 d_printf("Using the name [%s] from the server.\n", short_domain_name);
1285 d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
1288 short_domain_name = lp_workgroup();
1291 d_printf("Using short domain name -- %s\n", short_domain_name);
1293 /* HACK ALERT! Store the sid and password under both the lp_workgroup()
1294 value from smb.conf and the string returned from the server. The former is
1295 neede to bootstrap winbindd's first connection to the DC to get the real
1296 short domain name --jerry */
1298 if ( (store_domain_account( lp_workgroup(), domain_sid, password ) == -1)
1299 || (store_domain_account( short_domain_name, domain_sid, password ) == -1) )
1305 /* Verify that everything is ok */
1307 if ( net_rpc_join_ok(short_domain_name, ads->config.ldap_server_name, &ads->ldap_ip) != 0 ) {
1308 d_fprintf(stderr, "Failed to verify membership in domain!\n");
1312 /* From here on out, use the machine account. But first delete any
1313 existing tickets based on the user's creds. */
1315 ads_kdestroy( NULL );
1317 status = ADS_ERROR(LDAP_SERVER_DOWN);
1318 ads_s = ads_init( ads->server.realm, ads->server.workgroup, ads->server.ldap_server );
1321 asprintf( &ads_s->auth.user_name, "%s$", global_myname() );
1322 ads_s->auth.password = secrets_fetch_machine_password( short_domain_name, NULL, NULL );
1323 ads_s->auth.realm = SMB_STRDUP( lp_realm() );
1324 ads_kinit_password( ads_s );
1325 status = ads_connect( ads_s );
1327 if ( !ADS_ERR_OK(status) ) {
1328 d_fprintf( stderr, "LDAP bind using machine credentials failed!\n");
1329 d_fprintf(stderr, "Only NTLM authentication will be possible.\n");
1331 /* create the dNSHostName & servicePrincipalName values */
1333 status = net_set_machine_spn( ctx, ads_s );
1334 if ( !ADS_ERR_OK(status) ) {
1335 d_fprintf(stderr, "Failed to set servicePrincipalNames.\n");
1336 d_fprintf(stderr, "Only NTLM authentication will be possible.\n");
1342 ads_destroy( &ads_s );
1345 #if defined(HAVE_KRB5)
1346 if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
1347 d_fprintf(stderr, "asprintf failed\n");
1352 if (!kerberos_derive_salting_principal(machine_account)) {
1353 DEBUG(1,("Failed to determine salting principal\n"));
1358 if (!kerberos_derive_cifs_salting_principals()) {
1359 DEBUG(1,("Failed to determine salting principals\n"));
1364 /* Now build the keytab, using the same ADS connection */
1365 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
1366 DEBUG(1,("Error creating host keytab!\n"));
1370 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
1372 SAFE_FREE(machine_account);
1379 /*******************************************************************
1380 ********************************************************************/
1382 int net_ads_printer_usage(int argc, const char **argv)
1385 "\nnet ads printer search <printer>"
1386 "\n\tsearch for a printer in the directory\n"
1387 "\nnet ads printer info <printer> <server>"
1388 "\n\tlookup info in directory for printer on server"
1389 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1390 "\nnet ads printer publish <printername>"
1391 "\n\tpublish printer in directory"
1392 "\n\t(note: printer name is required)\n"
1393 "\nnet ads printer remove <printername>"
1394 "\n\tremove printer from directory"
1395 "\n\t(note: printer name is required)\n");
1399 /*******************************************************************
1400 ********************************************************************/
1402 static int net_ads_printer_search(int argc, const char **argv)
1408 if (!(ads = ads_startup())) {
1412 rc = ads_find_printers(ads, &res);
1414 if (!ADS_ERR_OK(rc)) {
1415 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1416 ads_msgfree(ads, res);
1421 if (ads_count_replies(ads, res) == 0) {
1422 d_fprintf(stderr, "No results found\n");
1423 ads_msgfree(ads, res);
1429 ads_msgfree(ads, res);
1434 static int net_ads_printer_info(int argc, const char **argv)
1438 const char *servername, *printername;
1441 if (!(ads = ads_startup())) {
1446 printername = argv[0];
1452 servername = argv[1];
1454 servername = global_myname();
1457 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1459 if (!ADS_ERR_OK(rc)) {
1460 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1461 ads_msgfree(ads, res);
1466 if (ads_count_replies(ads, res) == 0) {
1467 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1468 ads_msgfree(ads, res);
1474 ads_msgfree(ads, res);
1480 void do_drv_upgrade_printer(int msg_type, struct process_id src,
1481 void *buf, size_t len)
1486 static int net_ads_printer_publish(int argc, const char **argv)
1490 const char *servername, *printername;
1491 struct cli_state *cli;
1492 struct rpc_pipe_client *pipe_hnd;
1493 struct in_addr server_ip;
1495 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1496 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1497 char *prt_dn, *srv_dn, **srv_cn;
1500 if (!(ads = ads_startup())) {
1505 return net_ads_printer_usage(argc, argv);
1508 printername = argv[0];
1511 servername = argv[1];
1513 servername = global_myname();
1516 /* Get printer data from SPOOLSS */
1518 resolve_name(servername, &server_ip, 0x20);
1520 nt_status = cli_full_connection(&cli, global_myname(), servername,
1523 opt_user_name, opt_workgroup,
1524 opt_password ? opt_password : "",
1525 CLI_FULL_CONNECTION_USE_KERBEROS,
1528 if (NT_STATUS_IS_ERR(nt_status)) {
1529 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1530 "for %s\n", servername, printername);
1535 /* Publish on AD server */
1537 ads_find_machine_acct(ads, &res, servername);
1539 if (ads_count_replies(ads, res) == 0) {
1540 d_fprintf(stderr, "Could not find machine account for server %s\n",
1546 srv_dn = ldap_get_dn(ads->ld, res);
1547 srv_cn = ldap_explode_dn(srv_dn, 1);
1549 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
1551 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1553 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1559 get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1562 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1563 if (!ADS_ERR_OK(rc)) {
1564 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1569 d_printf("published printer\n");
1575 static int net_ads_printer_remove(int argc, const char **argv)
1579 const char *servername;
1583 if (!(ads = ads_startup())) {
1588 return net_ads_printer_usage(argc, argv);
1592 servername = argv[1];
1594 servername = global_myname();
1597 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1599 if (!ADS_ERR_OK(rc)) {
1600 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1601 ads_msgfree(ads, res);
1606 if (ads_count_replies(ads, res) == 0) {
1607 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1608 ads_msgfree(ads, res);
1613 prt_dn = ads_get_dn(ads, res);
1614 ads_msgfree(ads, res);
1615 rc = ads_del_dn(ads, prt_dn);
1616 ads_memfree(ads, prt_dn);
1618 if (!ADS_ERR_OK(rc)) {
1619 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1628 static int net_ads_printer(int argc, const char **argv)
1630 struct functable func[] = {
1631 {"SEARCH", net_ads_printer_search},
1632 {"INFO", net_ads_printer_info},
1633 {"PUBLISH", net_ads_printer_publish},
1634 {"REMOVE", net_ads_printer_remove},
1638 return net_run_function(argc, argv, func, net_ads_printer_usage);
1642 static int net_ads_password(int argc, const char **argv)
1645 const char *auth_principal = opt_user_name;
1646 const char *auth_password = opt_password;
1648 char *new_password = NULL;
1653 if (opt_user_name == NULL || opt_password == NULL) {
1654 d_fprintf(stderr, "You must supply an administrator username/password\n");
1659 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1664 if (!strchr_m(user, '@')) {
1665 asprintf(&c, "%s@%s", argv[0], lp_realm());
1669 use_in_memory_ccache();
1670 c = strchr_m(auth_principal, '@');
1677 /* use the realm so we can eventually change passwords for users
1678 in realms other than default */
1679 if (!(ads = ads_init(realm, NULL, NULL))) {
1683 /* we don't actually need a full connect, but it's the easy way to
1684 fill in the KDC's addresss */
1687 if (!ads || !ads->config.realm) {
1688 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1693 new_password = (char *)argv[1];
1695 asprintf(&prompt, "Enter new password for %s:", user);
1696 new_password = getpass(prompt);
1700 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1701 auth_password, user, new_password, ads->auth.time_offset);
1702 if (!ADS_ERR_OK(ret)) {
1703 d_fprintf(stderr, "Password change failed :-( ...\n");
1708 d_printf("Password change for %s completed.\n", user);
1714 int net_ads_changetrustpw(int argc, const char **argv)
1717 char *host_principal;
1721 if (!secrets_init()) {
1722 DEBUG(1,("Failed to initialise secrets database\n"));
1726 net_use_machine_password();
1728 use_in_memory_ccache();
1730 if (!(ads = ads_startup())) {
1734 fstrcpy(my_name, global_myname());
1735 strlower_m(my_name);
1736 asprintf(&host_principal, "%s@%s", my_name, ads->config.realm);
1737 d_printf("Changing password for principal: HOST/%s\n", host_principal);
1739 ret = ads_change_trust_account_password(ads, host_principal);
1741 if (!ADS_ERR_OK(ret)) {
1742 d_fprintf(stderr, "Password change failed :-( ...\n");
1744 SAFE_FREE(host_principal);
1748 d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
1750 if (lp_use_kerberos_keytab()) {
1751 d_printf("Attempting to update system keytab with new password.\n");
1752 if (ads_keytab_create_default(ads)) {
1753 d_printf("Failed to update system keytab.\n");
1758 SAFE_FREE(host_principal);
1764 help for net ads search
1766 static int net_ads_search_usage(int argc, const char **argv)
1769 "\nnet ads search <expression> <attributes...>\n"\
1770 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1771 "The expression is a standard LDAP search expression, and the\n"\
1772 "attributes are a list of LDAP fields to show in the results\n\n"\
1773 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1775 net_common_flags_usage(argc, argv);
1781 general ADS search function. Useful in diagnosing problems in ADS
1783 static int net_ads_search(int argc, const char **argv)
1787 const char *ldap_exp;
1792 return net_ads_search_usage(argc, argv);
1795 if (!(ads = ads_startup())) {
1802 rc = ads_do_search_all(ads, ads->config.bind_path,
1804 ldap_exp, attrs, &res);
1805 if (!ADS_ERR_OK(rc)) {
1806 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1811 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1813 /* dump the results */
1816 ads_msgfree(ads, res);
1824 help for net ads search
1826 static int net_ads_dn_usage(int argc, const char **argv)
1829 "\nnet ads dn <dn> <attributes...>\n"\
1830 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1831 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1832 "to show in the results\n\n"\
1833 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1835 net_common_flags_usage(argc, argv);
1841 general ADS search function. Useful in diagnosing problems in ADS
1843 static int net_ads_dn(int argc, const char **argv)
1852 return net_ads_dn_usage(argc, argv);
1855 if (!(ads = ads_startup())) {
1862 rc = ads_do_search_all(ads, dn,
1864 "(objectclass=*)", attrs, &res);
1865 if (!ADS_ERR_OK(rc)) {
1866 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1871 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1873 /* dump the results */
1876 ads_msgfree(ads, res);
1883 help for net ads sid search
1885 static int net_ads_sid_usage(int argc, const char **argv)
1888 "\nnet ads sid <sid> <attributes...>\n"\
1889 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1890 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
1891 "to show in the results\n\n"\
1892 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
1894 net_common_flags_usage(argc, argv);
1900 general ADS search function. Useful in diagnosing problems in ADS
1902 static int net_ads_sid(int argc, const char **argv)
1906 const char *sid_string;
1912 return net_ads_sid_usage(argc, argv);
1915 if (!(ads = ads_startup())) {
1919 sid_string = argv[0];
1922 if (!string_to_sid(&sid, sid_string)) {
1923 d_fprintf(stderr, "could not convert sid\n");
1928 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
1929 if (!ADS_ERR_OK(rc)) {
1930 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1935 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1937 /* dump the results */
1940 ads_msgfree(ads, res);
1947 static int net_ads_keytab_usage(int argc, const char **argv)
1950 "net ads keytab <COMMAND>\n"\
1951 "<COMMAND> can be either:\n"\
1952 " CREATE Creates a fresh keytab\n"\
1953 " ADD Adds new service principal\n"\
1954 " FLUSH Flushes out all keytab entries\n"\
1955 " HELP Prints this help message\n"\
1956 "The ADD command will take arguments, the other commands\n"\
1957 "will not take any arguments. The arguments given to ADD\n"\
1958 "should be a list of principals to add. For example, \n"\
1959 " net ads keytab add srv1 srv2\n"\
1960 "will add principals for the services srv1 and srv2 to the\n"\
1961 "system's keytab.\n"\
1967 static int net_ads_keytab_flush(int argc, const char **argv)
1972 if (!(ads = ads_startup())) {
1975 ret = ads_keytab_flush(ads);
1980 static int net_ads_keytab_add(int argc, const char **argv)
1986 d_printf("Processing principals to add...\n");
1987 if (!(ads = ads_startup())) {
1990 for (i = 0; i < argc; i++) {
1991 ret |= ads_keytab_add_entry(ads, argv[i]);
1997 static int net_ads_keytab_create(int argc, const char **argv)
2002 if (!(ads = ads_startup())) {
2005 ret = ads_keytab_create_default(ads);
2010 int net_ads_keytab(int argc, const char **argv)
2012 struct functable func[] = {
2013 {"CREATE", net_ads_keytab_create},
2014 {"ADD", net_ads_keytab_add},
2015 {"FLUSH", net_ads_keytab_flush},
2016 {"HELP", net_ads_keytab_usage},
2020 if (!lp_use_kerberos_keytab()) {
2021 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2022 use keytab functions.\n");
2025 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2028 int net_ads_help(int argc, const char **argv)
2030 struct functable func[] = {
2031 {"USER", net_ads_user_usage},
2032 {"GROUP", net_ads_group_usage},
2033 {"PRINTER", net_ads_printer_usage},
2034 {"SEARCH", net_ads_search_usage},
2036 {"INFO", net_ads_info},
2037 {"JOIN", net_ads_join},
2038 {"JOIN2", net_ads_join2},
2039 {"LEAVE", net_ads_leave},
2040 {"STATUS", net_ads_status},
2041 {"PASSWORD", net_ads_password},
2042 {"CHANGETRUSTPW", net_ads_changetrustpw},
2047 return net_run_function(argc, argv, func, net_ads_usage);
2050 int net_ads(int argc, const char **argv)
2052 struct functable func[] = {
2053 {"INFO", net_ads_info},
2054 {"JOIN", net_ads_join},
2055 {"TESTJOIN", net_ads_testjoin},
2056 {"LEAVE", net_ads_leave},
2057 {"STATUS", net_ads_status},
2058 {"USER", net_ads_user},
2059 {"GROUP", net_ads_group},
2060 {"PASSWORD", net_ads_password},
2061 {"CHANGETRUSTPW", net_ads_changetrustpw},
2062 {"PRINTER", net_ads_printer},
2063 {"SEARCH", net_ads_search},
2065 {"SID", net_ads_sid},
2066 {"WORKGROUP", net_ads_workgroup},
2067 {"LOOKUP", net_ads_lookup},
2068 {"KEYTAB", net_ads_keytab},
2069 {"HELP", net_ads_help},
2073 return net_run_function(argc, argv, func, net_ads_usage);
2078 static int net_ads_noads(void)
2080 d_fprintf(stderr, "ADS support not compiled in\n");
2084 int net_ads_keytab(int argc, const char **argv)
2086 return net_ads_noads();
2089 int net_ads_usage(int argc, const char **argv)
2091 return net_ads_noads();
2094 int net_ads_help(int argc, const char **argv)
2096 return net_ads_noads();
2099 int net_ads_changetrustpw(int argc, const char **argv)
2101 return net_ads_noads();
2104 int net_ads_join(int argc, const char **argv)
2106 return net_ads_noads();
2109 int net_ads_user(int argc, const char **argv)
2111 return net_ads_noads();
2114 int net_ads_group(int argc, const char **argv)
2116 return net_ads_noads();
2119 /* this one shouldn't display a message */
2120 int net_ads_check(void)
2125 int net_ads(int argc, const char **argv)
2127 return net_ads_usage(argc, argv);