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 3 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, see <http://www.gnu.org/licenses/>.
24 #include "utils/net.h"
26 #include "libnet/libnet.h"
30 int net_ads_usage(int argc
, const char **argv
)
32 d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
33 d_printf(" Join the local machine to a ADS realm\n");
35 d_printf(" Remove the local machine from a ADS realm\n");
36 d_printf("testjoin\n");
37 d_printf(" Validates the machine account in the domain\n");
39 d_printf(" List, add, or delete users in the realm\n");
41 d_printf(" List, add, or delete groups in the realm\n");
43 d_printf(" Displays details regarding a specific AD server\n");
45 d_printf(" Display details regarding the machine's account in AD\n");
47 d_printf(" Performs CLDAP query of AD domain controllers\n");
48 d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
49 d_printf(" Change a user's password using an admin account\n");
50 d_printf(" (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
51 d_printf("changetrustpw\n");
52 d_printf(" Change the trust account password of this machine in the AD tree\n");
53 d_printf("printer [info | publish | remove] <printername> <servername>\n");
54 d_printf(" Lookup, add, or remove directory entry for a printer\n");
55 d_printf("{search,dn,sid}\n");
56 d_printf(" Issue LDAP search queries using a general filter, by DN, or by SID\n");
58 d_printf(" Manage a local keytab file based on the machine account in AD\n");
60 d_printf(" Issue a dynamic DNS update request the server's hostname\n");
61 d_printf(" (using the machine credentials)\n");
66 /* when we do not have sufficient input parameters to contact a remote domain
67 * we always fall back to our own realm - Guenther*/
69 static const char *assume_own_realm(void)
71 if (!opt_host
&& strequal(lp_workgroup(), opt_target_workgroup
)) {
79 do a cldap netlogon query
81 static int net_ads_cldap_netlogon(ADS_STRUCT
*ads
)
83 char addr
[INET6_ADDRSTRLEN
];
84 struct nbt_cldap_netlogon_5 reply
;
86 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
87 if ( !ads_cldap_netlogon(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
88 d_fprintf(stderr
, "CLDAP query failed!\n");
92 d_printf("Information for Domain Controller: %s\n\n",
95 d_printf("Response Type: ");
97 case SAMLOGON_AD_UNK_R
:
98 d_printf("SAMLOGON\n");
101 d_printf("SAMLOGON_USER\n");
104 d_printf("0x%x\n", reply
.type
);
108 d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), reply
.domain_uuid
));
112 "\tIs a GC of the forest: %s\n"
113 "\tIs an LDAP server: %s\n"
114 "\tSupports DS: %s\n"
115 "\tIs running a KDC: %s\n"
116 "\tIs running time services: %s\n"
117 "\tIs the closest DC: %s\n"
118 "\tIs writable: %s\n"
119 "\tHas a hardware clock: %s\n"
120 "\tIs a non-domain NC serviced by LDAP server: %s\n",
121 (reply
.server_type
& NBT_SERVER_PDC
) ? "yes" : "no",
122 (reply
.server_type
& NBT_SERVER_GC
) ? "yes" : "no",
123 (reply
.server_type
& NBT_SERVER_LDAP
) ? "yes" : "no",
124 (reply
.server_type
& NBT_SERVER_DS
) ? "yes" : "no",
125 (reply
.server_type
& NBT_SERVER_KDC
) ? "yes" : "no",
126 (reply
.server_type
& NBT_SERVER_TIMESERV
) ? "yes" : "no",
127 (reply
.server_type
& NBT_SERVER_CLOSEST
) ? "yes" : "no",
128 (reply
.server_type
& NBT_SERVER_WRITABLE
) ? "yes" : "no",
129 (reply
.server_type
& NBT_SERVER_GOOD_TIMESERV
) ? "yes" : "no",
130 (reply
.server_type
& DS_SERVER_NDNC
) ? "yes" : "no");
132 printf("Forest:\t\t\t%s\n", reply
.forest
);
133 printf("Domain:\t\t\t%s\n", reply
.dns_domain
);
134 printf("Domain Controller:\t%s\n", reply
.pdc_dns_name
);
136 printf("Pre-Win2k Domain:\t%s\n", reply
.domain
);
137 printf("Pre-Win2k Hostname:\t%s\n", reply
.pdc_name
);
139 if (*reply
.user_name
) printf("User name:\t%s\n", reply
.user_name
);
141 printf("Server Site Name :\t\t%s\n", reply
.server_site
);
142 printf("Client Site Name :\t\t%s\n", reply
.client_site
);
144 d_printf("NT Version: %d\n", reply
.nt_version
);
145 d_printf("LMNT Token: %.2x\n", reply
.lmnt_token
);
146 d_printf("LM20 Token: %.2x\n", reply
.lm20_token
);
152 this implements the CLDAP based netlogon lookup requests
153 for finding the domain controller of a ADS domain
155 static int net_ads_lookup(int argc
, const char **argv
)
159 if (!ADS_ERR_OK(ads_startup_nobind(False
, &ads
))) {
160 d_fprintf(stderr
, "Didn't find the cldap server!\n");
164 if (!ads
->config
.realm
) {
165 ads
->config
.realm
= CONST_DISCARD(char *, opt_target_workgroup
);
166 ads
->ldap
.port
= 389;
169 return net_ads_cldap_netlogon(ads
);
174 static int net_ads_info(int argc
, const char **argv
)
177 char addr
[INET6_ADDRSTRLEN
];
179 if (!ADS_ERR_OK(ads_startup_nobind(False
, &ads
))) {
180 d_fprintf(stderr
, "Didn't find the ldap server!\n");
184 if (!ads
|| !ads
->config
.realm
) {
185 d_fprintf(stderr
, "Didn't find the ldap server!\n");
189 /* Try to set the server's current time since we didn't do a full
190 TCP LDAP session initially */
192 if ( !ADS_ERR_OK(ads_current_time( ads
)) ) {
193 d_fprintf( stderr
, "Failed to get server's current time!\n");
196 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
198 d_printf("LDAP server: %s\n", addr
);
199 d_printf("LDAP server name: %s\n", ads
->config
.ldap_server_name
);
200 d_printf("Realm: %s\n", ads
->config
.realm
);
201 d_printf("Bind Path: %s\n", ads
->config
.bind_path
);
202 d_printf("LDAP port: %d\n", ads
->ldap
.port
);
203 d_printf("Server time: %s\n", http_timestring(ads
->config
.current_time
));
205 d_printf("KDC server: %s\n", ads
->auth
.kdc_server
);
206 d_printf("Server time offset: %d\n", ads
->auth
.time_offset
);
211 static void use_in_memory_ccache(void) {
212 /* Use in-memory credentials cache so we do not interfere with
213 * existing credentials */
214 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
217 static ADS_STATUS
ads_startup_int(bool only_own_domain
, uint32 auth_flags
, ADS_STRUCT
**ads_ret
)
219 ADS_STRUCT
*ads
= NULL
;
221 bool need_password
= False
;
222 bool second_time
= False
;
224 const char *realm
= NULL
;
225 bool tried_closest_dc
= False
;
227 /* lp_realm() should be handled by a command line param,
228 However, the join requires that realm be set in smb.conf
229 and compares our realm with the remote server's so this is
230 ok until someone needs more flexibility */
235 if (only_own_domain
) {
238 realm
= assume_own_realm();
241 ads
= ads_init(realm
, opt_target_workgroup
, opt_host
);
243 if (!opt_user_name
) {
244 opt_user_name
= "administrator";
247 if (opt_user_specified
) {
248 need_password
= True
;
252 if (!opt_password
&& need_password
&& !opt_machine_pass
) {
253 opt_password
= net_prompt_pass(opt_user_name
);
256 return ADS_ERROR(LDAP_NO_MEMORY
);
261 use_in_memory_ccache();
262 SAFE_FREE(ads
->auth
.password
);
263 ads
->auth
.password
= smb_xstrdup(opt_password
);
266 ads
->auth
.flags
|= auth_flags
;
267 SAFE_FREE(ads
->auth
.user_name
);
268 ads
->auth
.user_name
= smb_xstrdup(opt_user_name
);
271 * If the username is of the form "name@realm",
272 * extract the realm and convert to upper case.
273 * This is only used to establish the connection.
275 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
277 SAFE_FREE(ads
->auth
.realm
);
278 ads
->auth
.realm
= smb_xstrdup(cp
);
279 strupper_m(ads
->auth
.realm
);
282 status
= ads_connect(ads
);
284 if (!ADS_ERR_OK(status
)) {
286 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
287 NT_STATUS_NO_LOGON_SERVERS
)) {
288 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
293 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
294 need_password
= True
;
303 /* when contacting our own domain, make sure we use the closest DC.
304 * This is done by reconnecting to ADS because only the first call to
305 * ads_connect will give us our own sitename */
307 if ((only_own_domain
|| !opt_host
) && !tried_closest_dc
) {
309 tried_closest_dc
= True
; /* avoid loop */
311 if (!ads
->config
.tried_closest_dc
) {
313 namecache_delete(ads
->server
.realm
, 0x1C);
314 namecache_delete(ads
->server
.workgroup
, 0x1C);
327 ADS_STATUS
ads_startup(bool only_own_domain
, ADS_STRUCT
**ads
)
329 return ads_startup_int(only_own_domain
, 0, ads
);
332 ADS_STATUS
ads_startup_nobind(bool only_own_domain
, ADS_STRUCT
**ads
)
334 return ads_startup_int(only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
338 Check to see if connection can be made via ads.
339 ads_startup() stores the password in opt_password if it needs to so
340 that rpc or rap can use it without re-prompting.
342 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
347 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
351 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
353 status
= ads_connect(ads
);
354 if ( !ADS_ERR_OK(status
) ) {
362 int net_ads_check_our_domain(void)
364 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
367 int net_ads_check(void)
369 return net_ads_check_int(NULL
, opt_workgroup
, opt_host
);
373 determine the netbios workgroup name for a domain
375 static int net_ads_workgroup(int argc
, const char **argv
)
378 char addr
[INET6_ADDRSTRLEN
];
379 struct nbt_cldap_netlogon_5 reply
;
381 if (!ADS_ERR_OK(ads_startup_nobind(False
, &ads
))) {
382 d_fprintf(stderr
, "Didn't find the cldap server!\n");
386 if (!ads
->config
.realm
) {
387 ads
->config
.realm
= CONST_DISCARD(char *, opt_target_workgroup
);
388 ads
->ldap
.port
= 389;
391 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
392 if ( !ads_cldap_netlogon(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
393 d_fprintf(stderr
, "CLDAP query failed!\n");
397 d_printf("Workgroup: %s\n", reply
.domain
);
406 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
408 char **disp_fields
= (char **) data_area
;
410 if (!field
) { /* must be end of record */
411 if (disp_fields
[0]) {
412 if (!strchr_m(disp_fields
[0], '$')) {
414 d_printf("%-21.21s %s\n",
415 disp_fields
[0], disp_fields
[1]);
417 d_printf("%s\n", disp_fields
[0]);
420 SAFE_FREE(disp_fields
[0]);
421 SAFE_FREE(disp_fields
[1]);
424 if (!values
) /* must be new field, indicate string field */
426 if (StrCaseCmp(field
, "sAMAccountName") == 0) {
427 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
429 if (StrCaseCmp(field
, "description") == 0)
430 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
434 static int net_ads_user_usage(int argc
, const char **argv
)
436 return net_help_user(argc
, argv
);
439 static int ads_user_add(int argc
, const char **argv
)
444 LDAPMessage
*res
=NULL
;
448 if (argc
< 1) return net_ads_user_usage(argc
, argv
);
450 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
454 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
456 if (!ADS_ERR_OK(status
)) {
457 d_fprintf(stderr
, "ads_user_add: %s\n", ads_errstr(status
));
461 if (ads_count_replies(ads
, res
)) {
462 d_fprintf(stderr
, "ads_user_add: User %s already exists\n", argv
[0]);
467 ou_str
= SMB_STRDUP(opt_container
);
469 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
472 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, opt_comment
);
474 if (!ADS_ERR_OK(status
)) {
475 d_fprintf(stderr
, "Could not add user %s: %s\n", argv
[0],
480 /* if no password is to be set, we're done */
482 d_printf("User %s added\n", argv
[0]);
487 /* try setting the password */
488 asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
);
489 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
490 ads
->auth
.time_offset
);
492 if (ADS_ERR_OK(status
)) {
493 d_printf("User %s added\n", argv
[0]);
498 /* password didn't set, delete account */
499 d_fprintf(stderr
, "Could not add user %s. Error setting password %s\n",
500 argv
[0], ads_errstr(status
));
501 ads_msgfree(ads
, res
);
502 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
503 if (ADS_ERR_OK(status
)) {
504 userdn
= ads_get_dn(ads
, res
);
505 ads_del_dn(ads
, userdn
);
506 ads_memfree(ads
, userdn
);
511 ads_msgfree(ads
, res
);
517 static int ads_user_info(int argc
, const char **argv
)
522 const char *attrs
[] = {"memberOf", NULL
};
523 char *searchstring
=NULL
;
528 return net_ads_user_usage(argc
, argv
);
531 escaped_user
= escape_ldap_string_alloc(argv
[0]);
534 d_fprintf(stderr
, "ads_user_info: failed to escape user %s\n", argv
[0]);
538 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
539 SAFE_FREE(escaped_user
);
543 asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
);
544 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
545 safe_free(searchstring
);
547 if (!ADS_ERR_OK(rc
)) {
548 d_fprintf(stderr
, "ads_search: %s\n", ads_errstr(rc
));
550 SAFE_FREE(escaped_user
);
554 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
555 (LDAPMessage
*)res
, "memberOf");
560 for (i
=0;grouplist
[i
];i
++) {
561 groupname
= ldap_explode_dn(grouplist
[i
], 1);
562 d_printf("%s\n", groupname
[0]);
563 ldap_value_free(groupname
);
565 ldap_value_free(grouplist
);
568 ads_msgfree(ads
, res
);
570 SAFE_FREE(escaped_user
);
574 static int ads_user_delete(int argc
, const char **argv
)
578 LDAPMessage
*res
= NULL
;
582 return net_ads_user_usage(argc
, argv
);
585 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
589 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
590 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
591 d_printf("User %s does not exist.\n", argv
[0]);
592 ads_msgfree(ads
, res
);
596 userdn
= ads_get_dn(ads
, res
);
597 ads_msgfree(ads
, res
);
598 rc
= ads_del_dn(ads
, userdn
);
599 ads_memfree(ads
, userdn
);
600 if (ADS_ERR_OK(rc
)) {
601 d_printf("User %s deleted\n", argv
[0]);
605 d_fprintf(stderr
, "Error deleting user %s: %s\n", argv
[0],
611 int net_ads_user(int argc
, const char **argv
)
613 struct functable func
[] = {
614 {"ADD", ads_user_add
},
615 {"INFO", ads_user_info
},
616 {"DELETE", ads_user_delete
},
621 const char *shortattrs
[] = {"sAMAccountName", NULL
};
622 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
623 char *disp_fields
[2] = {NULL
, NULL
};
626 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
630 if (opt_long_list_entries
)
631 d_printf("\nUser name Comment"\
632 "\n-----------------------------\n");
634 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
636 "(objectCategory=user)",
637 opt_long_list_entries
? longattrs
:
638 shortattrs
, usergrp_display
,
641 return ADS_ERR_OK(rc
) ? 0 : -1;
644 return net_run_function(argc
, argv
, func
, net_ads_user_usage
);
647 static int net_ads_group_usage(int argc
, const char **argv
)
649 return net_help_group(argc
, argv
);
652 static int ads_group_add(int argc
, const char **argv
)
656 LDAPMessage
*res
=NULL
;
661 return net_ads_group_usage(argc
, argv
);
664 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
668 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
670 if (!ADS_ERR_OK(status
)) {
671 d_fprintf(stderr
, "ads_group_add: %s\n", ads_errstr(status
));
675 if (ads_count_replies(ads
, res
)) {
676 d_fprintf(stderr
, "ads_group_add: Group %s already exists\n", argv
[0]);
681 ou_str
= SMB_STRDUP(opt_container
);
683 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
686 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, opt_comment
);
688 if (ADS_ERR_OK(status
)) {
689 d_printf("Group %s added\n", argv
[0]);
692 d_fprintf(stderr
, "Could not add group %s: %s\n", argv
[0],
698 ads_msgfree(ads
, res
);
704 static int ads_group_delete(int argc
, const char **argv
)
708 LDAPMessage
*res
= NULL
;
712 return net_ads_group_usage(argc
, argv
);
715 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
719 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
720 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
721 d_printf("Group %s does not exist.\n", argv
[0]);
722 ads_msgfree(ads
, res
);
726 groupdn
= ads_get_dn(ads
, res
);
727 ads_msgfree(ads
, res
);
728 rc
= ads_del_dn(ads
, groupdn
);
729 ads_memfree(ads
, groupdn
);
730 if (ADS_ERR_OK(rc
)) {
731 d_printf("Group %s deleted\n", argv
[0]);
735 d_fprintf(stderr
, "Error deleting group %s: %s\n", argv
[0],
741 int net_ads_group(int argc
, const char **argv
)
743 struct functable func
[] = {
744 {"ADD", ads_group_add
},
745 {"DELETE", ads_group_delete
},
750 const char *shortattrs
[] = {"sAMAccountName", NULL
};
751 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
752 char *disp_fields
[2] = {NULL
, NULL
};
755 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
759 if (opt_long_list_entries
)
760 d_printf("\nGroup name Comment"\
761 "\n-----------------------------\n");
762 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
764 "(objectCategory=group)",
765 opt_long_list_entries
? longattrs
:
766 shortattrs
, usergrp_display
,
770 return ADS_ERR_OK(rc
) ? 0 : -1;
772 return net_run_function(argc
, argv
, func
, net_ads_group_usage
);
775 static int net_ads_status(int argc
, const char **argv
)
781 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
785 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
786 if (!ADS_ERR_OK(rc
)) {
787 d_fprintf(stderr
, "ads_find_machine_acct: %s\n", ads_errstr(rc
));
792 if (ads_count_replies(ads
, res
) == 0) {
793 d_fprintf(stderr
, "No machine account for '%s' found\n", global_myname());
803 /*******************************************************************
804 Leave an AD domain. Windows XP disables the machine account.
805 We'll try the same. The old code would do an LDAP delete.
806 That only worked using the machine creds because added the machine
807 with full control to the computer object's ACL.
808 *******************************************************************/
810 static int net_ads_leave(int argc
, const char **argv
)
813 struct libnet_UnjoinCtx
*r
= NULL
;
817 d_fprintf(stderr
, "No realm set, are we joined ?\n");
821 if (!(ctx
= talloc_init("net_ads_leave"))) {
822 d_fprintf(stderr
, "Could not initialise talloc context.\n");
826 use_in_memory_ccache();
828 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
829 if (!W_ERROR_IS_OK(werr
)) {
830 d_fprintf(stderr
, "Could not initialise unjoin context.\n");
835 r
->in
.dc_name
= opt_host
;
836 r
->in
.domain_name
= lp_realm();
837 r
->in
.admin_account
= opt_user_name
;
838 r
->in
.admin_password
= net_prompt_pass(opt_user_name
);
839 r
->in
.modify_config
= lp_config_backend_is_registry();
840 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
841 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
843 werr
= libnet_Unjoin(ctx
, r
);
844 if (!W_ERROR_IS_OK(werr
)) {
845 d_printf("Failed to leave domain: %s\n",
846 r
->out
.error_string
? r
->out
.error_string
:
847 get_friendly_werror_msg(werr
));
851 if (W_ERROR_IS_OK(werr
)) {
852 d_printf("Deleted account for '%s' in realm '%s'\n",
853 r
->in
.machine_name
, r
->out
.dns_domain_name
);
857 /* We couldn't delete it - see if the disable succeeded. */
858 if (r
->out
.disabled_machine_account
) {
859 d_printf("Disabled account for '%s' in realm '%s'\n",
860 r
->in
.machine_name
, r
->out
.dns_domain_name
);
865 d_fprintf(stderr
, "Failed to disable machine account for '%s' in realm '%s'\n",
866 r
->in
.machine_name
, r
->out
.dns_domain_name
);
872 if (W_ERROR_IS_OK(werr
)) {
879 static NTSTATUS
net_ads_join_ok(void)
881 ADS_STRUCT
*ads
= NULL
;
884 if (!secrets_init()) {
885 DEBUG(1,("Failed to initialise secrets database\n"));
886 return NT_STATUS_ACCESS_DENIED
;
889 net_use_krb_machine_account();
891 status
= ads_startup(True
, &ads
);
892 if (!ADS_ERR_OK(status
)) {
893 return ads_ntstatus(status
);
901 check that an existing join is OK
903 int net_ads_testjoin(int argc
, const char **argv
)
906 use_in_memory_ccache();
908 /* Display success or failure */
909 status
= net_ads_join_ok();
910 if (!NT_STATUS_IS_OK(status
)) {
911 fprintf(stderr
,"Join to domain is not valid: %s\n",
912 get_friendly_nt_error_msg(status
));
916 printf("Join is OK\n");
920 /*******************************************************************
921 Simple configu checks before beginning the join
922 ********************************************************************/
924 static WERROR
check_ads_config( void )
926 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
927 d_printf("Host is not configured as a member server.\n");
928 return WERR_INVALID_DOMAIN_ROLE
;
931 if (strlen(global_myname()) > 15) {
932 d_printf("Our netbios name can be at most 15 chars long, "
933 "\"%s\" is %u chars long\n", global_myname(),
934 (unsigned int)strlen(global_myname()));
935 return WERR_INVALID_COMPUTER_NAME
;
938 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
939 d_fprintf(stderr
, "realm must be set in in %s for ADS "
940 "join to succeed.\n", get_dyn_CONFIGFILE());
941 return WERR_INVALID_PARAM
;
947 /*******************************************************************
948 Send a DNS update request
949 *******************************************************************/
951 #if defined(WITH_DNS_UPDATES)
953 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
954 const char *pszDomainName
, const char *pszHostName
,
955 const struct sockaddr_storage
*sslist
,
958 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
959 const char *machine_name
,
960 const struct sockaddr_storage
*addrs
,
963 struct dns_rr_ns
*nameservers
= NULL
;
965 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
968 const char *dnsdomain
= NULL
;
969 char *root_domain
= NULL
;
971 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
972 d_printf("No DNS domain configured for %s. "
973 "Unable to perform DNS Update.\n", machine_name
);
974 status
= NT_STATUS_INVALID_PARAMETER
;
979 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
980 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
981 /* Child domains often do not have NS records. Look
982 for the NS record for the forest root domain
983 (rootDomainNamingContext in therootDSE) */
985 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
986 LDAPMessage
*msg
= NULL
;
988 ADS_STATUS ads_status
;
990 if ( !ads
->ldap
.ld
) {
991 ads_status
= ads_connect( ads
);
992 if ( !ADS_ERR_OK(ads_status
) ) {
993 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
998 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
999 "(objectclass=*)", rootname_attrs
, &msg
);
1000 if (!ADS_ERR_OK(ads_status
)) {
1004 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1006 ads_msgfree( ads
, msg
);
1010 root_domain
= ads_build_domain( root_dn
);
1013 ads_msgfree( ads
, msg
);
1015 /* try again for NS servers */
1017 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1019 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1020 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1021 "realm\n", ads
->config
.realm
));
1025 dnsdomain
= root_domain
;
1029 /* Now perform the dns update - we'll try non-secure and if we fail,
1030 we'll follow it up with a secure update */
1032 fstrcpy( dns_server
, nameservers
[0].hostname
);
1034 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1035 if (!ERR_DNS_IS_OK(dns_err
)) {
1036 status
= NT_STATUS_UNSUCCESSFUL
;
1041 SAFE_FREE( root_domain
);
1046 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
)
1049 struct sockaddr_storage
*iplist
= NULL
;
1050 fstring machine_name
;
1053 name_to_fqdn( machine_name
, global_myname() );
1054 strlower_m( machine_name
);
1056 /* Get our ip address (not the 127.0.0.x address but a real ip
1059 num_addrs
= get_my_ip_address( &iplist
);
1060 if ( num_addrs
<= 0 ) {
1061 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1063 return NT_STATUS_INVALID_PARAMETER
;
1066 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1068 SAFE_FREE( iplist
);
1074 /*******************************************************************
1075 ********************************************************************/
1077 static int net_ads_join_usage(int argc
, const char **argv
)
1079 d_printf("net ads join [options]\n");
1080 d_printf("Valid options:\n");
1081 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1082 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1083 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1084 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1085 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1086 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1087 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1088 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1089 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1090 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1091 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1092 d_printf(" the two other attributes.\n");
1097 /*******************************************************************
1098 ********************************************************************/
1100 int net_ads_join(int argc
, const char **argv
)
1102 TALLOC_CTX
*ctx
= NULL
;
1103 struct libnet_JoinCtx
*r
= NULL
;
1104 const char *domain
= lp_realm();
1105 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1106 bool createupn
= False
;
1107 const char *machineupn
= NULL
;
1108 const char *create_in_ou
= NULL
;
1110 const char *os_name
= NULL
;
1111 const char *os_version
= NULL
;
1112 bool modify_config
= lp_config_backend_is_registry();
1114 if (!modify_config
) {
1116 werr
= check_ads_config();
1117 if (!W_ERROR_IS_OK(werr
)) {
1118 d_fprintf(stderr
, "Invalid configuration. Exiting....\n");
1123 if (!(ctx
= talloc_init("net_ads_join"))) {
1124 d_fprintf(stderr
, "Could not initialise talloc context.\n");
1129 use_in_memory_ccache();
1131 werr
= libnet_init_JoinCtx(ctx
, &r
);
1132 if (!W_ERROR_IS_OK(werr
)) {
1136 /* process additional command line args */
1138 for ( i
=0; i
<argc
; i
++ ) {
1139 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1141 machineupn
= get_string_param(argv
[i
]);
1143 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1144 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1145 d_fprintf(stderr
, "Please supply a valid OU path.\n");
1146 werr
= WERR_INVALID_PARAM
;
1150 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1151 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1152 d_fprintf(stderr
, "Please supply a operating system name.\n");
1153 werr
= WERR_INVALID_PARAM
;
1157 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1158 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1159 d_fprintf(stderr
, "Please supply a valid operating system version.\n");
1160 werr
= WERR_INVALID_PARAM
;
1170 d_fprintf(stderr
, "Please supply a valid domain name\n");
1171 werr
= WERR_INVALID_PARAM
;
1175 /* Do the domain join here */
1177 r
->in
.domain_name
= domain
;
1178 r
->in
.create_upn
= createupn
;
1179 r
->in
.upn
= machineupn
;
1180 r
->in
.account_ou
= create_in_ou
;
1181 r
->in
.os_name
= os_name
;
1182 r
->in
.os_version
= os_version
;
1183 r
->in
.dc_name
= opt_host
;
1184 r
->in
.admin_account
= opt_user_name
;
1185 r
->in
.admin_password
= net_prompt_pass(opt_user_name
);
1187 r
->in
.modify_config
= modify_config
;
1188 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1189 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1190 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1192 werr
= libnet_Join(ctx
, r
);
1193 if (!W_ERROR_IS_OK(werr
)) {
1197 /* Check the short name of the domain */
1199 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1200 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1201 d_printf("domain name obtained from the server.\n");
1202 d_printf("Using the name [%s] from the server.\n", r
->out
.netbios_domain_name
);
1203 d_printf("You should set \"workgroup = %s\" in %s.\n",
1204 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1207 d_printf("Using short domain name -- %s\n", r
->out
.netbios_domain_name
);
1209 if (r
->out
.dns_domain_name
) {
1210 d_printf("Joined '%s' to realm '%s'\n", r
->in
.machine_name
,
1211 r
->out
.dns_domain_name
);
1213 d_printf("Joined '%s' to domain '%s'\n", r
->in
.machine_name
,
1214 r
->out
.netbios_domain_name
);
1217 #if defined(WITH_DNS_UPDATES)
1218 if (r
->out
.domain_is_ad
) {
1219 /* We enter this block with user creds */
1220 ADS_STRUCT
*ads_dns
= NULL
;
1222 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1223 /* kinit with the machine password */
1225 use_in_memory_ccache();
1226 asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname() );
1227 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1228 r
->out
.netbios_domain_name
, NULL
, NULL
);
1229 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1230 ads_kinit_password( ads_dns
);
1233 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns( ctx
, ads_dns
)) ) {
1234 d_fprintf( stderr
, "DNS update failed!\n" );
1237 /* exit from this block using machine creds */
1238 ads_destroy(&ads_dns
);
1247 /* issue an overall failure message at the end. */
1248 d_printf("Failed to join domain: %s\n",
1249 r
&& r
->out
.error_string
? r
->out
.error_string
:
1250 get_friendly_werror_msg(werr
));
1256 /*******************************************************************
1257 ********************************************************************/
1259 static int net_ads_dns_usage(int argc
, const char **argv
)
1261 #if defined(WITH_DNS_UPDATES)
1262 d_printf("net ads dns <command>\n");
1263 d_printf("Valid commands:\n");
1264 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1268 d_fprintf(stderr
, "DNS update support not enabled at compile time!\n");
1273 /*******************************************************************
1274 ********************************************************************/
1276 static int net_ads_dns_register(int argc
, const char **argv
)
1278 #if defined(WITH_DNS_UPDATES)
1284 talloc_enable_leak_report();
1288 d_fprintf(stderr
, "net ads dns register\n");
1292 if (!(ctx
= talloc_init("net_ads_dns"))) {
1293 d_fprintf(stderr
, "Could not initialise talloc context\n");
1297 status
= ads_startup(True
, &ads
);
1298 if ( !ADS_ERR_OK(status
) ) {
1299 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1304 if ( !NT_STATUS_IS_OK(net_update_dns(ctx
, ads
)) ) {
1305 d_fprintf( stderr
, "DNS update failed!\n" );
1306 ads_destroy( &ads
);
1311 d_fprintf( stderr
, "Successfully registered hostname with DNS\n" );
1318 d_fprintf(stderr
, "DNS update support not enabled at compile time!\n");
1323 #if defined(WITH_DNS_UPDATES)
1324 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1327 static int net_ads_dns_gethostbyname(int argc
, const char **argv
)
1329 #if defined(WITH_DNS_UPDATES)
1333 talloc_enable_leak_report();
1337 d_fprintf(stderr
, "net ads dns gethostbyname <server> "
1342 err
= do_gethostbyname(argv
[0], argv
[1]);
1344 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err
));
1349 static int net_ads_dns(int argc
, const char *argv
[])
1351 struct functable func
[] = {
1352 {"REGISTER", net_ads_dns_register
},
1353 {"GETHOSTBYNAME", net_ads_dns_gethostbyname
},
1357 return net_run_function(argc
, argv
, func
, net_ads_dns_usage
);
1360 /*******************************************************************
1361 ********************************************************************/
1363 int net_ads_printer_usage(int argc
, const char **argv
)
1366 "\nnet ads printer search <printer>"
1367 "\n\tsearch for a printer in the directory\n"
1368 "\nnet ads printer info <printer> <server>"
1369 "\n\tlookup info in directory for printer on server"
1370 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1371 "\nnet ads printer publish <printername>"
1372 "\n\tpublish printer in directory"
1373 "\n\t(note: printer name is required)\n"
1374 "\nnet ads printer remove <printername>"
1375 "\n\tremove printer from directory"
1376 "\n\t(note: printer name is required)\n");
1380 /*******************************************************************
1381 ********************************************************************/
1383 static int net_ads_printer_search(int argc
, const char **argv
)
1387 LDAPMessage
*res
= NULL
;
1389 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
1393 rc
= ads_find_printers(ads
, &res
);
1395 if (!ADS_ERR_OK(rc
)) {
1396 d_fprintf(stderr
, "ads_find_printer: %s\n", ads_errstr(rc
));
1397 ads_msgfree(ads
, res
);
1402 if (ads_count_replies(ads
, res
) == 0) {
1403 d_fprintf(stderr
, "No results found\n");
1404 ads_msgfree(ads
, res
);
1410 ads_msgfree(ads
, res
);
1415 static int net_ads_printer_info(int argc
, const char **argv
)
1419 const char *servername
, *printername
;
1420 LDAPMessage
*res
= NULL
;
1422 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
1427 printername
= argv
[0];
1433 servername
= argv
[1];
1435 servername
= global_myname();
1438 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1440 if (!ADS_ERR_OK(rc
)) {
1441 d_fprintf(stderr
, "Server '%s' not found: %s\n",
1442 servername
, ads_errstr(rc
));
1443 ads_msgfree(ads
, res
);
1448 if (ads_count_replies(ads
, res
) == 0) {
1449 d_fprintf(stderr
, "Printer '%s' not found\n", printername
);
1450 ads_msgfree(ads
, res
);
1456 ads_msgfree(ads
, res
);
1462 static int net_ads_printer_publish(int argc
, const char **argv
)
1466 const char *servername
, *printername
;
1467 struct cli_state
*cli
;
1468 struct rpc_pipe_client
*pipe_hnd
;
1469 struct sockaddr_storage server_ss
;
1471 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1472 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1473 char *prt_dn
, *srv_dn
, **srv_cn
;
1474 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1475 LDAPMessage
*res
= NULL
;
1477 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
1478 talloc_destroy(mem_ctx
);
1483 talloc_destroy(mem_ctx
);
1484 return net_ads_printer_usage(argc
, argv
);
1487 printername
= argv
[0];
1490 servername
= argv
[1];
1492 servername
= global_myname();
1495 /* Get printer data from SPOOLSS */
1497 resolve_name(servername
, &server_ss
, 0x20);
1499 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1502 opt_user_name
, opt_workgroup
,
1503 opt_password
? opt_password
: "",
1504 CLI_FULL_CONNECTION_USE_KERBEROS
,
1507 if (NT_STATUS_IS_ERR(nt_status
)) {
1508 d_fprintf(stderr
, "Unable to open a connnection to %s to obtain data "
1509 "for %s\n", servername
, printername
);
1511 talloc_destroy(mem_ctx
);
1515 /* Publish on AD server */
1517 ads_find_machine_acct(ads
, &res
, servername
);
1519 if (ads_count_replies(ads
, res
) == 0) {
1520 d_fprintf(stderr
, "Could not find machine account for server %s\n",
1523 talloc_destroy(mem_ctx
);
1527 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1528 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1530 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1531 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1532 if (!srv_cn_escaped
|| !printername_escaped
) {
1533 SAFE_FREE(srv_cn_escaped
);
1534 SAFE_FREE(printername_escaped
);
1535 d_fprintf(stderr
, "Internal error, out of memory!");
1537 talloc_destroy(mem_ctx
);
1541 asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
);
1543 SAFE_FREE(srv_cn_escaped
);
1544 SAFE_FREE(printername_escaped
);
1546 pipe_hnd
= cli_rpc_pipe_open_noauth(cli
, PI_SPOOLSS
, &nt_status
);
1548 d_fprintf(stderr
, "Unable to open a connnection to the spoolss pipe on %s\n",
1552 talloc_destroy(mem_ctx
);
1556 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1560 talloc_destroy(mem_ctx
);
1564 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1565 if (!ADS_ERR_OK(rc
)) {
1566 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1569 talloc_destroy(mem_ctx
);
1573 d_printf("published printer\n");
1576 talloc_destroy(mem_ctx
);
1581 static int net_ads_printer_remove(int argc
, const char **argv
)
1585 const char *servername
;
1587 LDAPMessage
*res
= NULL
;
1589 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
1594 return net_ads_printer_usage(argc
, argv
);
1598 servername
= argv
[1];
1600 servername
= global_myname();
1603 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1605 if (!ADS_ERR_OK(rc
)) {
1606 d_fprintf(stderr
, "ads_find_printer_on_server: %s\n", ads_errstr(rc
));
1607 ads_msgfree(ads
, res
);
1612 if (ads_count_replies(ads
, res
) == 0) {
1613 d_fprintf(stderr
, "Printer '%s' not found\n", argv
[1]);
1614 ads_msgfree(ads
, res
);
1619 prt_dn
= ads_get_dn(ads
, res
);
1620 ads_msgfree(ads
, res
);
1621 rc
= ads_del_dn(ads
, prt_dn
);
1622 ads_memfree(ads
, prt_dn
);
1624 if (!ADS_ERR_OK(rc
)) {
1625 d_fprintf(stderr
, "ads_del_dn: %s\n", ads_errstr(rc
));
1634 static int net_ads_printer(int argc
, const char **argv
)
1636 struct functable func
[] = {
1637 {"SEARCH", net_ads_printer_search
},
1638 {"INFO", net_ads_printer_info
},
1639 {"PUBLISH", net_ads_printer_publish
},
1640 {"REMOVE", net_ads_printer_remove
},
1644 return net_run_function(argc
, argv
, func
, net_ads_printer_usage
);
1648 static int net_ads_password(int argc
, const char **argv
)
1651 const char *auth_principal
= opt_user_name
;
1652 const char *auth_password
= opt_password
;
1654 char *new_password
= NULL
;
1659 if (opt_user_name
== NULL
|| opt_password
== NULL
) {
1660 d_fprintf(stderr
, "You must supply an administrator username/password\n");
1665 d_fprintf(stderr
, "ERROR: You must say which username to change password for\n");
1670 if (!strchr_m(user
, '@')) {
1671 asprintf(&c
, "%s@%s", argv
[0], lp_realm());
1675 use_in_memory_ccache();
1676 c
= strchr_m(auth_principal
, '@');
1683 /* use the realm so we can eventually change passwords for users
1684 in realms other than default */
1685 if (!(ads
= ads_init(realm
, opt_workgroup
, opt_host
))) {
1689 /* we don't actually need a full connect, but it's the easy way to
1690 fill in the KDC's addresss */
1693 if (!ads
->config
.realm
) {
1694 d_fprintf(stderr
, "Didn't find the kerberos server!\n");
1699 new_password
= (char *)argv
[1];
1701 asprintf(&prompt
, "Enter new password for %s:", user
);
1702 new_password
= getpass(prompt
);
1706 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
1707 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
1708 if (!ADS_ERR_OK(ret
)) {
1709 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1714 d_printf("Password change for %s completed.\n", user
);
1720 int net_ads_changetrustpw(int argc
, const char **argv
)
1723 char *host_principal
;
1727 if (!secrets_init()) {
1728 DEBUG(1,("Failed to initialise secrets database\n"));
1732 net_use_krb_machine_account();
1734 use_in_memory_ccache();
1736 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
1740 fstrcpy(my_name
, global_myname());
1741 strlower_m(my_name
);
1742 asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
);
1743 d_printf("Changing password for principal: %s\n", host_principal
);
1745 ret
= ads_change_trust_account_password(ads
, host_principal
);
1747 if (!ADS_ERR_OK(ret
)) {
1748 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1750 SAFE_FREE(host_principal
);
1754 d_printf("Password change for principal %s succeeded.\n", host_principal
);
1756 if (lp_use_kerberos_keytab()) {
1757 d_printf("Attempting to update system keytab with new password.\n");
1758 if (ads_keytab_create_default(ads
)) {
1759 d_printf("Failed to update system keytab.\n");
1764 SAFE_FREE(host_principal
);
1770 help for net ads search
1772 static int net_ads_search_usage(int argc
, const char **argv
)
1775 "\nnet ads search <expression> <attributes...>\n"\
1776 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1777 "The expression is a standard LDAP search expression, and the\n"\
1778 "attributes are a list of LDAP fields to show in the results\n\n"\
1779 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1781 net_common_flags_usage(argc
, argv
);
1787 general ADS search function. Useful in diagnosing problems in ADS
1789 static int net_ads_search(int argc
, const char **argv
)
1793 const char *ldap_exp
;
1795 LDAPMessage
*res
= NULL
;
1798 return net_ads_search_usage(argc
, argv
);
1801 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
1808 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
1810 ldap_exp
, attrs
, &res
);
1811 if (!ADS_ERR_OK(rc
)) {
1812 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
1817 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
1819 /* dump the results */
1822 ads_msgfree(ads
, res
);
1830 help for net ads search
1832 static int net_ads_dn_usage(int argc
, const char **argv
)
1835 "\nnet ads dn <dn> <attributes...>\n"\
1836 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1837 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1838 "to show in the results\n\n"\
1839 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1840 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1842 net_common_flags_usage(argc
, argv
);
1848 general ADS search function. Useful in diagnosing problems in ADS
1850 static int net_ads_dn(int argc
, const char **argv
)
1856 LDAPMessage
*res
= NULL
;
1859 return net_ads_dn_usage(argc
, argv
);
1862 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
1869 rc
= ads_do_search_all(ads
, dn
,
1871 "(objectclass=*)", attrs
, &res
);
1872 if (!ADS_ERR_OK(rc
)) {
1873 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
1878 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
1880 /* dump the results */
1883 ads_msgfree(ads
, res
);
1890 help for net ads sid search
1892 static int net_ads_sid_usage(int argc
, const char **argv
)
1895 "\nnet ads sid <sid> <attributes...>\n"\
1896 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1897 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
1898 "to show in the results\n\n"\
1899 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
1901 net_common_flags_usage(argc
, argv
);
1907 general ADS search function. Useful in diagnosing problems in ADS
1909 static int net_ads_sid(int argc
, const char **argv
)
1913 const char *sid_string
;
1915 LDAPMessage
*res
= NULL
;
1919 return net_ads_sid_usage(argc
, argv
);
1922 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
1926 sid_string
= argv
[0];
1929 if (!string_to_sid(&sid
, sid_string
)) {
1930 d_fprintf(stderr
, "could not convert sid\n");
1935 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
1936 if (!ADS_ERR_OK(rc
)) {
1937 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
1942 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
1944 /* dump the results */
1947 ads_msgfree(ads
, res
);
1954 static int net_ads_keytab_usage(int argc
, const char **argv
)
1957 "net ads keytab <COMMAND>\n"\
1958 "<COMMAND> can be either:\n"\
1959 " ADD Adds new service principal\n"\
1960 " CREATE Creates a fresh keytab\n"\
1961 " FLUSH Flushes out all keytab entries\n"\
1962 " HELP Prints this help message\n"\
1963 " LIST List the keytab\n"\
1964 "The ADD and LIST command will take arguments, the other commands\n"\
1965 "will not take any arguments. The arguments given to ADD\n"\
1966 "should be a list of principals to add. For example, \n"\
1967 " net ads keytab add srv1 srv2\n"\
1968 "will add principals for the services srv1 and srv2 to the\n"\
1969 "system's keytab.\n"\
1970 "The LIST command takes a keytabname.\n"\
1976 static int net_ads_keytab_flush(int argc
, const char **argv
)
1981 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
1984 ret
= ads_keytab_flush(ads
);
1989 static int net_ads_keytab_add(int argc
, const char **argv
)
1995 d_printf("Processing principals to add...\n");
1996 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
1999 for (i
= 0; i
< argc
; i
++) {
2000 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2006 static int net_ads_keytab_create(int argc
, const char **argv
)
2011 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
2014 ret
= ads_keytab_create_default(ads
);
2019 static int net_ads_keytab_list(int argc
, const char **argv
)
2021 const char *keytab
= NULL
;
2027 return ads_keytab_list(keytab
);
2031 int net_ads_keytab(int argc
, const char **argv
)
2033 struct functable func
[] = {
2034 {"ADD", net_ads_keytab_add
},
2035 {"CREATE", net_ads_keytab_create
},
2036 {"FLUSH", net_ads_keytab_flush
},
2037 {"HELP", net_ads_keytab_usage
},
2038 {"LIST", net_ads_keytab_list
},
2042 if (!lp_use_kerberos_keytab()) {
2043 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2044 use keytab functions.\n");
2047 return net_run_function(argc
, argv
, func
, net_ads_keytab_usage
);
2050 static int net_ads_kerberos_usage(int argc
, const char **argv
)
2053 "net ads kerberos <COMMAND>\n"\
2054 "<COMMAND> can be either:\n"\
2055 " RENEW Renew TGT from existing credential cache\n"\
2056 " PAC Dumps the Kerberos PAC\n"\
2057 " KINIT Retrieve Ticket Granting Ticket (TGT)\n"\
2064 static int net_ads_kerberos_renew(int argc
, const char **argv
)
2066 int ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2068 d_printf("failed to renew kerberos ticket: %s\n",
2069 error_message(ret
));
2074 static int net_ads_kerberos_pac(int argc
, const char **argv
)
2076 struct PAC_DATA
*pac
= NULL
;
2077 struct PAC_LOGON_INFO
*info
= NULL
;
2078 TALLOC_CTX
*mem_ctx
= NULL
;
2082 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2087 opt_password
= net_prompt_pass(opt_user_name
);
2089 status
= kerberos_return_pac(mem_ctx
,
2098 2592000, /* one month */
2100 if (!NT_STATUS_IS_OK(status
)) {
2101 d_printf("failed to query kerberos PAC: %s\n",
2106 info
= get_logon_info_from_pac(pac
);
2109 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2110 d_printf("The Pac: %s\n", s
);
2115 TALLOC_FREE(mem_ctx
);
2119 static int net_ads_kerberos_kinit(int argc
, const char **argv
)
2121 TALLOC_CTX
*mem_ctx
= NULL
;
2125 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2130 opt_password
= net_prompt_pass(opt_user_name
);
2132 ret
= kerberos_kinit_password_ext(opt_user_name
,
2140 2592000, /* one month */
2143 d_printf("failed to kinit password: %s\n",
2150 int net_ads_kerberos(int argc
, const char **argv
)
2152 struct functable func
[] = {
2153 {"KINIT", net_ads_kerberos_kinit
},
2154 {"RENEW", net_ads_kerberos_renew
},
2155 {"PAC", net_ads_kerberos_pac
},
2156 {"HELP", net_ads_kerberos_usage
},
2160 return net_run_function(argc
, argv
, func
, net_ads_kerberos_usage
);
2164 int net_ads_help(int argc
, const char **argv
)
2166 struct functable func
[] = {
2167 {"USER", net_ads_user_usage
},
2168 {"GROUP", net_ads_group_usage
},
2169 {"PRINTER", net_ads_printer_usage
},
2170 {"SEARCH", net_ads_search_usage
},
2171 {"INFO", net_ads_info
},
2172 {"JOIN", net_ads_join_usage
},
2173 {"DNS", net_ads_dns_usage
},
2174 {"LEAVE", net_ads_leave
},
2175 {"STATUS", net_ads_status
},
2176 {"PASSWORD", net_ads_password
},
2177 {"CHANGETRUSTPW", net_ads_changetrustpw
},
2181 return net_run_function(argc
, argv
, func
, net_ads_usage
);
2184 int net_ads(int argc
, const char **argv
)
2186 struct functable func
[] = {
2187 {"INFO", net_ads_info
},
2188 {"JOIN", net_ads_join
},
2189 {"TESTJOIN", net_ads_testjoin
},
2190 {"LEAVE", net_ads_leave
},
2191 {"STATUS", net_ads_status
},
2192 {"USER", net_ads_user
},
2193 {"GROUP", net_ads_group
},
2194 {"DNS", net_ads_dns
},
2195 {"PASSWORD", net_ads_password
},
2196 {"CHANGETRUSTPW", net_ads_changetrustpw
},
2197 {"PRINTER", net_ads_printer
},
2198 {"SEARCH", net_ads_search
},
2200 {"SID", net_ads_sid
},
2201 {"WORKGROUP", net_ads_workgroup
},
2202 {"LOOKUP", net_ads_lookup
},
2203 {"KEYTAB", net_ads_keytab
},
2204 {"GPO", net_ads_gpo
},
2205 {"KERBEROS", net_ads_kerberos
},
2206 {"HELP", net_ads_help
},
2210 return net_run_function(argc
, argv
, func
, net_ads_usage
);
2215 static int net_ads_noads(void)
2217 d_fprintf(stderr
, "ADS support not compiled in\n");
2221 int net_ads_keytab(int argc
, const char **argv
)
2223 return net_ads_noads();
2226 int net_ads_kerberos(int argc
, const char **argv
)
2228 return net_ads_noads();
2231 int net_ads_usage(int argc
, const char **argv
)
2233 return net_ads_noads();
2236 int net_ads_help(int argc
, const char **argv
)
2238 return net_ads_noads();
2241 int net_ads_changetrustpw(int argc
, const char **argv
)
2243 return net_ads_noads();
2246 int net_ads_join(int argc
, const char **argv
)
2248 return net_ads_noads();
2251 int net_ads_user(int argc
, const char **argv
)
2253 return net_ads_noads();
2256 int net_ads_group(int argc
, const char **argv
)
2258 return net_ads_noads();
2261 /* this one shouldn't display a message */
2262 int net_ads_check(void)
2267 int net_ads_check_our_domain(void)
2272 int net_ads(int argc
, const char **argv
)
2274 return net_ads_usage(argc
, argv
);
2277 #endif /* WITH_ADS */