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"
29 int net_ads_usage(int argc, const char **argv)
31 d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
32 d_printf(" Join the local machine to a ADS realm\n");
34 d_printf(" Remove the local machine from a ADS realm\n");
35 d_printf("testjoin\n");
36 d_printf(" Validates the machine account in the domain\n");
38 d_printf(" List, add, or delete users in the realm\n");
40 d_printf(" List, add, or delete groups in the realm\n");
42 d_printf(" Displays details regarding a specific AD server\n");
44 d_printf(" Display details regarding the machine's account in AD\n");
46 d_printf(" Performs CLDAP query of AD domain controllers\n");
47 d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
48 d_printf(" Change a user's password using an admin account\n");
49 d_printf(" (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
50 d_printf("changetrustpw\n");
51 d_printf(" Change the trust account password of this machine in the AD tree\n");
52 d_printf("printer [info | publish | remove] <printername> <servername>\n");
53 d_printf(" Lookup, add, or remove directory entry for a printer\n");
54 d_printf("{search,dn,sid}\n");
55 d_printf(" Issue LDAP search queries using a general filter, by DN, or by SID\n");
57 d_printf(" Manage a local keytab file based on the machine account in AD\n");
59 d_printf(" Issue a dynamic DNS update request the server's hostname\n");
60 d_printf(" (using the machine credentials)\n");
65 /* when we do not have sufficient input parameters to contact a remote domain
66 * we always fall back to our own realm - Guenther*/
68 static const char *assume_own_realm(void)
70 if (!opt_host && strequal(lp_workgroup(), opt_target_workgroup)) {
78 do a cldap netlogon query
80 static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
82 struct cldap_netlogon_reply reply;
84 if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap_ip), ads->server.realm, &reply ) ) {
85 d_fprintf(stderr, "CLDAP query failed!\n");
89 d_printf("Information for Domain Controller: %s\n\n",
90 inet_ntoa(ads->ldap_ip));
92 d_printf("Response Type: ");
94 case SAMLOGON_AD_UNK_R:
95 d_printf("SAMLOGON\n");
98 d_printf("SAMLOGON_USER\n");
101 d_printf("0x%x\n", reply.type);
104 d_printf("GUID: %s\n",
105 smb_uuid_string_static(smb_uuid_unpack_static(reply.guid)));
108 "\tIs a GC of the forest: %s\n"
109 "\tIs an LDAP server: %s\n"
110 "\tSupports DS: %s\n"
111 "\tIs running a KDC: %s\n"
112 "\tIs running time services: %s\n"
113 "\tIs the closest DC: %s\n"
114 "\tIs writable: %s\n"
115 "\tHas a hardware clock: %s\n"
116 "\tIs a non-domain NC serviced by LDAP server: %s\n",
117 (reply.flags & ADS_PDC) ? "yes" : "no",
118 (reply.flags & ADS_GC) ? "yes" : "no",
119 (reply.flags & ADS_LDAP) ? "yes" : "no",
120 (reply.flags & ADS_DS) ? "yes" : "no",
121 (reply.flags & ADS_KDC) ? "yes" : "no",
122 (reply.flags & ADS_TIMESERV) ? "yes" : "no",
123 (reply.flags & ADS_CLOSEST) ? "yes" : "no",
124 (reply.flags & ADS_WRITABLE) ? "yes" : "no",
125 (reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
126 (reply.flags & ADS_NDNC) ? "yes" : "no");
128 printf("Forest:\t\t\t%s\n", reply.forest);
129 printf("Domain:\t\t\t%s\n", reply.domain);
130 printf("Domain Controller:\t%s\n", reply.hostname);
132 printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
133 printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
135 if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
136 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
138 printf("Server Site Name :\t\t%s\n", reply.server_site_name);
139 printf("Client Site Name :\t\t%s\n", reply.client_site_name);
141 d_printf("NT Version: %d\n", reply.version);
142 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
143 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
150 this implements the CLDAP based netlogon lookup requests
151 for finding the domain controller of a ADS domain
153 static int net_ads_lookup(int argc, const char **argv)
157 const char *realm = assume_own_realm();
159 ads = ads_init(realm, opt_target_workgroup, opt_host);
161 ads->auth.flags |= ADS_AUTH_NO_BIND;
164 status = ads_connect(ads);
165 if (!ADS_ERR_OK(status) || !ads) {
166 d_fprintf(stderr, "Didn't find the cldap server!\n");
170 if (!ads->config.realm) {
171 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
172 ads->ldap_port = 389;
175 return net_ads_cldap_netlogon(ads);
180 static int net_ads_info(int argc, const char **argv)
183 const char *realm = assume_own_realm();
185 if ( (ads = ads_init(realm, opt_target_workgroup, opt_host)) != NULL ) {
186 ads->auth.flags |= ADS_AUTH_NO_BIND;
191 if (!ads || !ads->config.realm) {
192 d_fprintf(stderr, "Didn't find the ldap server!\n");
196 /* Try to set the server's current time since we didn't do a full
197 TCP LDAP session initially */
199 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
200 d_fprintf( stderr, "Failed to get server's current time!\n");
203 d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
204 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
205 d_printf("Realm: %s\n", ads->config.realm);
206 d_printf("Bind Path: %s\n", ads->config.bind_path);
207 d_printf("LDAP port: %d\n", ads->ldap_port);
208 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
210 d_printf("KDC server: %s\n", ads->auth.kdc_server );
211 d_printf("Server time offset: %d\n", ads->auth.time_offset );
216 static void use_in_memory_ccache(void) {
217 /* Use in-memory credentials cache so we do not interfere with
218 * existing credentials */
219 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
222 ADS_STATUS ads_startup(BOOL only_own_domain, ADS_STRUCT **ads)
225 BOOL need_password = False;
226 BOOL second_time = False;
228 const char *realm = NULL;
230 /* lp_realm() should be handled by a command line param,
231 However, the join requires that realm be set in smb.conf
232 and compares our realm with the remote server's so this is
233 ok until someone needs more flexibility */
235 if (only_own_domain) {
239 *ads = ads_init(realm, opt_target_workgroup, opt_host);
241 if (!opt_user_name) {
242 opt_user_name = "administrator";
245 if (opt_user_specified) {
246 need_password = True;
250 if (!opt_password && need_password && !opt_machine_pass) {
252 asprintf(&prompt,"%s's password: ", opt_user_name);
253 opt_password = getpass(prompt);
258 use_in_memory_ccache();
259 (*ads)->auth.password = smb_xstrdup(opt_password);
262 (*ads)->auth.user_name = smb_xstrdup(opt_user_name);
265 * If the username is of the form "name@realm",
266 * extract the realm and convert to upper case.
267 * This is only used to establish the connection.
269 if ((cp = strchr_m((*ads)->auth.user_name, '@'))!=0) {
271 (*ads)->auth.realm = smb_xstrdup(cp);
272 strupper_m((*ads)->auth.realm);
275 status = ads_connect(*ads);
277 if (!ADS_ERR_OK(status)) {
278 if (!need_password && !second_time) {
279 need_password = True;
291 Check to see if connection can be made via ads.
292 ads_startup() stores the password in opt_password if it needs to so
293 that rpc or rap can use it without re-prompting.
295 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
300 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
304 ads->auth.flags |= ADS_AUTH_NO_BIND;
306 status = ads_connect(ads);
307 if ( !ADS_ERR_OK(status) ) {
315 int net_ads_check_our_domain(void)
317 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
320 int net_ads_check(void)
322 return net_ads_check_int(NULL, opt_workgroup, opt_host);
325 determine the netbios workgroup name for a domain
327 static int net_ads_workgroup(int argc, const char **argv)
331 const char *realm = assume_own_realm();
332 struct cldap_netlogon_reply reply;
334 ads = ads_init(realm, opt_target_workgroup, opt_host);
336 ads->auth.flags |= ADS_AUTH_NO_BIND;
339 status = ads_connect(ads);
340 if (!ADS_ERR_OK(status) || !ads) {
341 d_fprintf(stderr, "Didn't find the cldap server!\n");
345 if (!ads->config.realm) {
346 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
347 ads->ldap_port = 389;
350 if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap_ip), ads->server.realm, &reply ) ) {
351 d_fprintf(stderr, "CLDAP query failed!\n");
355 d_printf("Workgroup: %s\n", reply.netbios_domain);
364 static BOOL usergrp_display(char *field, void **values, void *data_area)
366 char **disp_fields = (char **) data_area;
368 if (!field) { /* must be end of record */
369 if (disp_fields[0]) {
370 if (!strchr_m(disp_fields[0], '$')) {
372 d_printf("%-21.21s %s\n",
373 disp_fields[0], disp_fields[1]);
375 d_printf("%s\n", disp_fields[0]);
378 SAFE_FREE(disp_fields[0]);
379 SAFE_FREE(disp_fields[1]);
382 if (!values) /* must be new field, indicate string field */
384 if (StrCaseCmp(field, "sAMAccountName") == 0) {
385 disp_fields[0] = SMB_STRDUP((char *) values[0]);
387 if (StrCaseCmp(field, "description") == 0)
388 disp_fields[1] = SMB_STRDUP((char *) values[0]);
392 static int net_ads_user_usage(int argc, const char **argv)
394 return net_help_user(argc, argv);
397 static int ads_user_add(int argc, const char **argv)
402 LDAPMessage *res=NULL;
405 if (argc < 1) return net_ads_user_usage(argc, argv);
407 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
411 status = ads_find_user_acct(ads, &res, argv[0]);
413 if (!ADS_ERR_OK(status)) {
414 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
418 if (ads_count_replies(ads, res)) {
419 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
423 if (opt_container == NULL) {
424 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
427 status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
429 if (!ADS_ERR_OK(status)) {
430 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
435 /* if no password is to be set, we're done */
437 d_printf("User %s added\n", argv[0]);
442 /* try setting the password */
443 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
444 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
445 ads->auth.time_offset);
447 if (ADS_ERR_OK(status)) {
448 d_printf("User %s added\n", argv[0]);
453 /* password didn't set, delete account */
454 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
455 argv[0], ads_errstr(status));
456 ads_msgfree(ads, res);
457 status=ads_find_user_acct(ads, &res, argv[0]);
458 if (ADS_ERR_OK(status)) {
459 userdn = ads_get_dn(ads, res);
460 ads_del_dn(ads, userdn);
461 ads_memfree(ads, userdn);
466 ads_msgfree(ads, res);
471 static int ads_user_info(int argc, const char **argv)
476 const char *attrs[] = {"memberOf", NULL};
477 char *searchstring=NULL;
482 return net_ads_user_usage(argc, argv);
485 escaped_user = escape_ldap_string_alloc(argv[0]);
488 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
492 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
493 SAFE_FREE(escaped_user);
497 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
498 rc = ads_search(ads, &res, searchstring, attrs);
499 safe_free(searchstring);
501 if (!ADS_ERR_OK(rc)) {
502 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
504 SAFE_FREE(escaped_user);
508 grouplist = ldap_get_values((LDAP *)ads->ld,
509 (LDAPMessage *)res, "memberOf");
514 for (i=0;grouplist[i];i++) {
515 groupname = ldap_explode_dn(grouplist[i], 1);
516 d_printf("%s\n", groupname[0]);
517 ldap_value_free(groupname);
519 ldap_value_free(grouplist);
522 ads_msgfree(ads, res);
524 SAFE_FREE(escaped_user);
528 static int ads_user_delete(int argc, const char **argv)
536 return net_ads_user_usage(argc, argv);
539 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
543 rc = ads_find_user_acct(ads, &res, argv[0]);
544 if (!ADS_ERR_OK(rc)) {
545 d_printf("User %s does not exist.\n", argv[0]);
549 userdn = ads_get_dn(ads, res);
550 ads_msgfree(ads, res);
551 rc = ads_del_dn(ads, userdn);
552 ads_memfree(ads, userdn);
553 if (!ADS_ERR_OK(rc)) {
554 d_printf("User %s deleted\n", argv[0]);
558 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
564 int net_ads_user(int argc, const char **argv)
566 struct functable func[] = {
567 {"ADD", ads_user_add},
568 {"INFO", ads_user_info},
569 {"DELETE", ads_user_delete},
574 const char *shortattrs[] = {"sAMAccountName", NULL};
575 const char *longattrs[] = {"sAMAccountName", "description", NULL};
576 char *disp_fields[2] = {NULL, NULL};
579 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
583 if (opt_long_list_entries)
584 d_printf("\nUser name Comment"\
585 "\n-----------------------------\n");
587 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
589 "(objectCategory=user)",
590 opt_long_list_entries ? longattrs :
591 shortattrs, usergrp_display,
594 return ADS_ERR_OK(rc) ? 0 : -1;
597 return net_run_function(argc, argv, func, net_ads_user_usage);
600 static int net_ads_group_usage(int argc, const char **argv)
602 return net_help_group(argc, argv);
605 static int ads_group_add(int argc, const char **argv)
609 LDAPMessage *res=NULL;
613 return net_ads_group_usage(argc, argv);
616 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
620 status = ads_find_user_acct(ads, &res, argv[0]);
622 if (!ADS_ERR_OK(status)) {
623 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
627 if (ads_count_replies(ads, res)) {
628 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
629 ads_msgfree(ads, res);
633 if (opt_container == NULL) {
634 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
637 status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
639 if (ADS_ERR_OK(status)) {
640 d_printf("Group %s added\n", argv[0]);
643 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
649 ads_msgfree(ads, res);
654 static int ads_group_delete(int argc, const char **argv)
662 return net_ads_group_usage(argc, argv);
665 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
669 rc = ads_find_user_acct(ads, &res, argv[0]);
670 if (!ADS_ERR_OK(rc)) {
671 d_printf("Group %s does not exist.\n", argv[0]);
675 groupdn = ads_get_dn(ads, res);
676 ads_msgfree(ads, res);
677 rc = ads_del_dn(ads, groupdn);
678 ads_memfree(ads, groupdn);
679 if (!ADS_ERR_OK(rc)) {
680 d_printf("Group %s deleted\n", argv[0]);
684 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
690 int net_ads_group(int argc, const char **argv)
692 struct functable func[] = {
693 {"ADD", ads_group_add},
694 {"DELETE", ads_group_delete},
699 const char *shortattrs[] = {"sAMAccountName", NULL};
700 const char *longattrs[] = {"sAMAccountName", "description", NULL};
701 char *disp_fields[2] = {NULL, NULL};
704 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
708 if (opt_long_list_entries)
709 d_printf("\nGroup name Comment"\
710 "\n-----------------------------\n");
711 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
713 "(objectCategory=group)",
714 opt_long_list_entries ? longattrs :
715 shortattrs, usergrp_display,
719 return ADS_ERR_OK(rc) ? 0 : -1;
721 return net_run_function(argc, argv, func, net_ads_group_usage);
724 static int net_ads_status(int argc, const char **argv)
730 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
734 rc = ads_find_machine_acct(ads, &res, global_myname());
735 if (!ADS_ERR_OK(rc)) {
736 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
741 if (ads_count_replies(ads, res) == 0) {
742 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
752 /*******************************************************************
753 Leave an AD domain. Windows XP disables the machine account.
754 We'll try the same. The old code would do an LDAP delete.
755 That only worked using the machine creds because added the machine
756 with full control to the computer object's ACL.
757 *******************************************************************/
759 static int net_ads_leave(int argc, const char **argv)
761 ADS_STRUCT *ads = NULL;
765 struct cli_state *cli = NULL;
767 DOM_SID *dom_sid = NULL;
769 if (!secrets_init()) {
770 DEBUG(1,("Failed to initialise secrets database\n"));
774 if (!(ctx = talloc_init("net_ads_leave"))) {
775 d_fprintf(stderr, "Could not initialise talloc context.\n");
779 /* The finds a DC and takes care of getting the
780 user creds if necessary */
782 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
786 /* make RPC calls here */
788 if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, &ads->ldap_ip,
789 ads->config.ldap_server_name)) )
794 saf_store( cli->server_domain, cli->desthost );
796 if ( !NT_STATUS_IS_OK(netdom_get_domain_sid( ctx, cli, &dom_sid )) ) {
800 status = netdom_leave_domain(ctx, cli, dom_sid);
802 /* Ty and delete it via LDAP - the old way we used to. */
804 adsret = ads_leave_realm(ads, global_myname());
805 if (ADS_ERR_OK(adsret)) {
806 d_printf("Deleted account for '%s' in realm '%s'\n",
807 global_myname(), ads->config.realm);
810 /* We couldn't delete it - see if the disable succeeded. */
811 if (NT_STATUS_IS_OK(status)) {
812 d_printf("Disabled account for '%s' in realm '%s'\n",
813 global_myname(), ads->config.realm);
816 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
817 global_myname(), ads->config.realm);
832 static NTSTATUS net_ads_join_ok(void)
834 ADS_STRUCT *ads = NULL;
837 if (!secrets_init()) {
838 DEBUG(1,("Failed to initialise secrets database\n"));
839 return NT_STATUS_ACCESS_DENIED;
842 net_use_machine_password();
844 status = ads_startup(True, &ads);
845 if (!ADS_ERR_OK(status)) {
846 return ads_ntstatus(status);
854 check that an existing join is OK
856 int net_ads_testjoin(int argc, const char **argv)
859 use_in_memory_ccache();
861 /* Display success or failure */
862 status = net_ads_join_ok();
863 if (!NT_STATUS_IS_OK(status)) {
864 fprintf(stderr,"Join to domain is not valid: %s\n",
865 get_friendly_nt_error_msg(status));
869 printf("Join is OK\n");
873 /*******************************************************************
874 Simple configu checks before beginning the join
875 ********************************************************************/
877 static NTSTATUS check_ads_config( void )
879 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
880 d_printf("Host is not configured as a member server.\n");
881 return NT_STATUS_INVALID_DOMAIN_ROLE;
884 if (strlen(global_myname()) > 15) {
885 d_printf("Our netbios name can be at most 15 chars long, "
886 "\"%s\" is %u chars long\n", global_myname(),
887 (unsigned int)strlen(global_myname()));
888 return NT_STATUS_NAME_TOO_LONG;
891 if ( lp_security() == SEC_ADS && !*lp_realm()) {
892 d_fprintf(stderr, "realm must be set in in smb.conf for ADS "
893 "join to succeed.\n");
894 return NT_STATUS_INVALID_PARAMETER;
897 if (!secrets_init()) {
898 DEBUG(1,("Failed to initialise secrets database\n"));
899 /* This is a good bet for failure of secrets_init ... */
900 return NT_STATUS_ACCESS_DENIED;
906 /*******************************************************************
908 ********************************************************************/
910 static NTSTATUS net_join_domain(TALLOC_CTX *ctx, const char *servername,
911 struct in_addr *ip, DOM_SID **dom_sid,
912 const char *password)
914 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
915 struct cli_state *cli = NULL;
917 ret = connect_to_ipc_krb5(&cli, ip, servername);
918 if ( !NT_STATUS_IS_OK(ret) ) {
922 saf_store( cli->server_domain, cli->desthost );
924 ret = netdom_get_domain_sid( ctx, cli, dom_sid );
925 if ( !NT_STATUS_IS_OK(ret) ) {
929 ret = netdom_join_domain( ctx, cli, *dom_sid, password, ND_TYPE_AD );
938 /*******************************************************************
939 Set a machines dNSHostName and servicePrincipalName attributes
940 ********************************************************************/
942 static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
944 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
947 const char *servicePrincipalName[3] = {NULL, NULL, NULL};
950 LDAPMessage *res = NULL;
951 char *dn_string = NULL;
952 const char *machine_name = global_myname();
955 if ( !machine_name ) {
956 return ADS_ERROR(LDAP_NO_MEMORY);
961 status = ads_find_machine_acct(ads_s, &res, machine_name);
962 if (!ADS_ERR_OK(status))
965 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
966 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
967 return ADS_ERROR(LDAP_NO_MEMORY);
970 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
971 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
975 new_dn = talloc_strdup(ctx, dn_string);
976 ads_memfree(ads_s, dn_string);
978 return ADS_ERROR(LDAP_NO_MEMORY);
981 /* Windows only creates HOST/shortname & HOST/fqdn. */
983 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) )
986 servicePrincipalName[0] = psp;
988 name_to_fqdn(my_fqdn, machine_name);
990 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) )
992 servicePrincipalName[1] = psp;
994 if (!(mods = ads_init_mods(ctx))) {
998 /* fields of primary importance */
1000 ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
1001 ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
1003 status = ads_gen_mod(ads_s, new_dn, mods);
1006 ads_msgfree(ads_s, res);
1011 /*******************************************************************
1012 Set a machines dNSHostName and servicePrincipalName attributes
1013 ********************************************************************/
1015 static ADS_STATUS net_set_machine_upn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, const char *upn )
1017 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1020 LDAPMessage *res = NULL;
1021 char *dn_string = NULL;
1022 const char *machine_name = global_myname();
1025 if ( !machine_name ) {
1026 return ADS_ERROR(LDAP_NO_MEMORY);
1031 status = ads_find_machine_acct(ads_s, &res, machine_name);
1032 if (!ADS_ERR_OK(status))
1035 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1036 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1037 return ADS_ERROR(LDAP_NO_MEMORY);
1040 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1041 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1045 new_dn = talloc_strdup(ctx, dn_string);
1046 ads_memfree(ads_s, dn_string);
1048 return ADS_ERROR(LDAP_NO_MEMORY);
1051 /* now do the mods */
1053 if (!(mods = ads_init_mods(ctx))) {
1057 /* fields of primary importance */
1059 ads_mod_str(ctx, &mods, "userPrincipalName", upn);
1061 status = ads_gen_mod(ads_s, new_dn, mods);
1064 ads_msgfree(ads_s, res);
1069 /*******************************************************************
1070 join a domain using ADS (LDAP mods)
1071 ********************************************************************/
1073 static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
1075 ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
1077 LDAPMessage *res = NULL;
1079 ou_str = ads_ou_string(ads, ou);
1080 asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
1083 rc = ads_search_dn(ads, &res, dn, NULL);
1084 ads_msgfree(ads, res);
1086 if (ADS_ERR_OK(rc)) {
1087 /* Attempt to create the machine account and bail if this fails.
1088 Assume that the admin wants exactly what they requested */
1090 rc = ads_create_machine_acct( ads, global_myname(), dn );
1091 if ( rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS ) {
1101 /************************************************************************
1102 ************************************************************************/
1104 static BOOL net_derive_salting_principal( TALLOC_CTX *ctx, ADS_STRUCT *ads )
1110 LDAPMessage *res = NULL;
1111 const char *machine_name = global_myname();
1113 status = ads_domain_func_level( ads, &domain_func );
1114 if ( !ADS_ERR_OK(status) ) {
1115 DEBUG(2,("Failed to determine domain functional level!\n"));
1119 /* go ahead and setup the default salt */
1121 if ( (std_salt = kerberos_standard_des_salt()) == NULL ) {
1122 d_fprintf(stderr, "net_derive_salting_principal: failed to obtain stanard DES salt\n");
1126 fstrcpy( salt, std_salt );
1127 SAFE_FREE( std_salt );
1129 /* if it's a Windows functional domain, we have to look for the UPN */
1131 if ( domain_func == DS_DOMAIN_FUNCTION_2000 ) {
1135 status = ads_find_machine_acct(ads, &res, machine_name);
1136 if (!ADS_ERR_OK(status)) {
1140 if ( (count = ads_count_replies(ads, res)) != 1 ) {
1141 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1145 upn = ads_pull_string(ads, ctx, res, "userPrincipalName");
1147 fstrcpy( salt, upn );
1150 ads_msgfree(ads, res);
1153 return kerberos_secrets_store_des_salt( salt );
1156 /*******************************************************************
1157 Send a DNS update request
1158 *******************************************************************/
1160 #if defined(WITH_DNS_UPDATES)
1161 static BOOL net_update_dns( TALLOC_CTX *ctx, ADS_STRUCT *ads )
1164 struct in_addr *iplist = NULL;
1165 struct dns_rr_ns *nameservers = NULL;
1168 NTSTATUS dns_status;
1169 fstring machine_name;
1171 const char *dnsdomain;
1172 ADS_STRUCT *ads_s = NULL;
1174 name_to_fqdn( machine_name, global_myname() );
1175 strlower_m( machine_name );
1177 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1178 d_printf("No DNS domain configured for %s. Unable to perform DNS Update.\n",
1184 dns_status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1185 if ( !NT_STATUS_IS_OK(dns_status) || (ns_count == 0)) {
1186 DEBUG(3,("net_ads_join: Failed to find name server for the %s realm\n",
1187 ads->config.realm));
1191 /* Get our ip address (not the 127.0.0.x address but a real ip address) */
1193 num_addrs = get_my_ip_address( &iplist );
1194 if ( num_addrs <= 0 ) {
1195 DEBUG(4,("net_ads_join: Failed to find my non-loopback IP addresses!\n"));
1200 /* Drop the user creds */
1202 ads_kdestroy( NULL );
1204 ads_s = ads_init( ads->server.realm, ads->server.workgroup, ads->server.ldap_server );
1206 DEBUG(1,("net_ads_join: ads_init() failed!\n"));
1211 /* kinit with the machine password */
1213 asprintf( &ads_s->auth.user_name, "%s$", global_myname() );
1214 ads_s->auth.password = secrets_fetch_machine_password( lp_workgroup(), NULL, NULL );
1215 ads_s->auth.realm = SMB_STRDUP( lp_realm() );
1216 ads_kinit_password( ads_s );
1218 /* Now perform the dns update - we'll try non-secure and if we fail, we'll
1219 follow it up with a secure update */
1221 fstrcpy( dns_server, nameservers[0].hostname );
1223 ret = DoDNSUpdate(dns_server, dnsdomain, machine_name, iplist, num_addrs );
1225 DEBUG(1, ("Error creating dns update!\n"));
1229 SAFE_FREE( iplist );
1231 ads_destroy( &ads_s );
1238 /*******************************************************************
1239 utility function to parse an integer parameter from
1241 **********************************************************/
1242 static char* get_string_param( const char* param )
1246 if ( (p = strchr( param, '=' )) == NULL )
1252 /*******************************************************************
1253 ********************************************************************/
1255 static int net_ads_join_usage(int argc, const char **argv)
1257 d_printf("net ads join [options]\n");
1258 d_printf("Valid options:\n");
1259 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1260 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1261 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1262 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1263 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1268 /*******************************************************************
1269 ********************************************************************/
1271 int net_ads_join(int argc, const char **argv)
1273 ADS_STRUCT *ads = NULL;
1276 char *machine_account = NULL;
1277 const char *short_domain_name = NULL;
1278 char *tmp_password, *password;
1279 struct cldap_netlogon_reply cldap_reply;
1280 TALLOC_CTX *ctx = NULL;
1281 DOM_SID *domain_sid = NULL;
1282 BOOL createupn = False;
1283 const char *machineupn = NULL;
1284 const char *create_in_ou = NULL;
1287 nt_status = check_ads_config();
1288 if (!NT_STATUS_IS_OK(nt_status)) {
1289 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1293 status = ads_startup(True, &ads);
1294 if (!ADS_ERR_OK(status)) {
1295 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1296 nt_status = ads_ntstatus(status);
1300 if (strcmp(ads->config.realm, lp_realm()) != 0) {
1301 d_fprintf(stderr, "realm of remote server (%s) and realm in smb.conf "
1302 "(%s) DO NOT match. Aborting join\n", ads->config.realm,
1304 nt_status = NT_STATUS_INVALID_PARAMETER;
1308 if (!(ctx = talloc_init("net_ads_join"))) {
1309 d_fprintf(stderr, "Could not initialise talloc context.\n");
1310 nt_status = NT_STATUS_NO_MEMORY;
1314 /* process additional command line args */
1316 for ( i=0; i<argc; i++ ) {
1317 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1319 machineupn = get_string_param(argv[i]);
1321 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1322 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1323 d_fprintf(stderr, "Please supply a valid OU path\n");
1324 nt_status = NT_STATUS_INVALID_PARAMETER;
1329 d_fprintf(stderr, "Bad option: %s\n", argv[i]);
1330 nt_status = NT_STATUS_INVALID_PARAMETER;
1335 /* If we were given an OU, try to create the machine in
1336 the OU account first and then do the normal RPC join */
1338 if ( create_in_ou ) {
1339 status = net_precreate_machine_acct( ads, create_in_ou );
1340 if ( !ADS_ERR_OK(status) ) {
1341 d_fprintf( stderr, "Failed to pre-create the machine object "
1342 "in OU %s.\n", argv[0]);
1343 DEBUG(1, ("error calling net_precreate_machine_acct: %s\n",
1344 ads_errstr(status)));
1345 nt_status = ads_ntstatus(status);
1350 /* Do the domain join here */
1352 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1353 password = talloc_strdup(ctx, tmp_password);
1355 nt_status = net_join_domain(ctx, ads->config.ldap_server_name,
1356 &ads->ldap_ip, &domain_sid, password);
1357 if ( !NT_STATUS_IS_OK(nt_status) ) {
1358 DEBUG(1, ("call of net_join_domain failed: %s\n",
1359 get_friendly_nt_error_msg(nt_status)));
1363 /* Check the short name of the domain */
1365 ZERO_STRUCT( cldap_reply );
1367 if ( ads_cldap_netlogon( ads->config.ldap_server_name,
1368 ads->server.realm, &cldap_reply ) )
1370 short_domain_name = talloc_strdup( ctx, cldap_reply.netbios_domain );
1371 if ( !strequal(lp_workgroup(), short_domain_name) ) {
1372 d_printf("The workgroup in smb.conf does not match the short\n");
1373 d_printf("domain name obtained from the server.\n");
1374 d_printf("Using the name [%s] from the server.\n", short_domain_name);
1375 d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
1378 short_domain_name = lp_workgroup();
1381 d_printf("Using short domain name -- %s\n", short_domain_name);
1383 /* HACK ALERT! Store the sid and password under both the lp_workgroup()
1384 value from smb.conf and the string returned from the server. The former is
1385 neede to bootstrap winbindd's first connection to the DC to get the real
1386 short domain name --jerry */
1388 if ( (netdom_store_machine_account( lp_workgroup(), domain_sid, password ) == -1)
1389 || (netdom_store_machine_account( short_domain_name, domain_sid, password ) == -1) )
1391 /* issue an internal error here for now.
1392 * everything else would mean changing tdb routines. */
1393 nt_status = NT_STATUS_INTERNAL_ERROR;
1397 /* Verify that everything is ok */
1399 if ( net_rpc_join_ok(short_domain_name, ads->config.ldap_server_name, &ads->ldap_ip) != 0 ) {
1400 d_fprintf(stderr, "Failed to verify membership in domain!\n");
1404 /* create the dNSHostName & servicePrincipalName values */
1406 status = net_set_machine_spn( ctx, ads );
1407 if ( !ADS_ERR_OK(status) ) {
1409 d_fprintf(stderr, "Failed to set servicePrincipalNames. Please ensure that\n");
1410 d_fprintf(stderr, "the DNS domain of this server matches the AD domain,\n");
1411 d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n");
1413 /* Disable the machine account in AD. Better to fail than to leave
1414 a confused admin. */
1416 if ( net_ads_leave( 0, NULL ) != 0 ) {
1417 d_fprintf( stderr, "Failed to disable machine account in AD. Please do so manually.\n");
1420 /* clear out the machine password */
1422 netdom_store_machine_account( lp_workgroup(), domain_sid, "" );
1423 netdom_store_machine_account( short_domain_name, domain_sid, "" );
1425 nt_status = ads_ntstatus(status);
1429 if ( !net_derive_salting_principal( ctx, ads ) ) {
1430 DEBUG(1,("Failed to determine salting principal\n"));
1437 /* default to using the short UPN name */
1438 if ( !machineupn ) {
1439 snprintf( upn, sizeof(upn), "host/%s@%s", global_myname(),
1440 ads->config.realm );
1444 status = net_set_machine_upn( ctx, ads, machineupn );
1445 if ( !ADS_ERR_OK(status) ) {
1446 d_fprintf(stderr, "Failed to set userPrincipalName. Are you a Domain Admin?\n");
1450 /* Now build the keytab, using the same ADS connection */
1451 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
1452 DEBUG(1,("Error creating host keytab!\n"));
1455 #if defined(WITH_DNS_UPDATES)
1456 /* We enter this block with user creds */
1458 if ( !net_update_dns( ctx, ads ) ) {
1459 d_fprintf( stderr, "DNS update failed!\n" );
1462 /* exit from this block using machine creds */
1465 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
1467 SAFE_FREE(machine_account);
1474 /* issue an overall failure message at the end. */
1475 d_printf("Failed to join domain: %s\n", get_friendly_nt_error_msg(nt_status));
1477 SAFE_FREE(machine_account);
1485 /*******************************************************************
1486 ********************************************************************/
1488 static int net_ads_dns_usage(int argc, const char **argv)
1490 #if defined(WITH_DNS_UPDATES)
1491 d_printf("net ads dns <command>\n");
1492 d_printf("Valid commands:\n");
1493 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1497 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1502 /*******************************************************************
1503 ********************************************************************/
1505 static int net_ads_dns(int argc, const char **argv)
1507 #if defined(WITH_DNS_UPDATES)
1511 BOOL register_dns = False;
1514 status = ads_startup(True, &ads);
1515 if ( !ADS_ERR_OK(status) ) {
1516 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1520 if (!(ctx = talloc_init("net_ads_dns"))) {
1521 DEBUG(0, ("Could not initialise talloc context\n"));
1525 /* process additional command line args */
1527 for ( i=0; i<argc; i++ ) {
1528 if ( strequal(argv[i], "register") ) {
1529 register_dns = True;
1532 d_fprintf(stderr, "Bad option: %s\n", argv[i]);
1537 if ( !net_update_dns( ctx, ads ) ) {
1538 d_fprintf( stderr, "DNS update failed!\n" );
1539 ads_destroy( &ads );
1544 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1551 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1556 /*******************************************************************
1557 ********************************************************************/
1559 int net_ads_printer_usage(int argc, const char **argv)
1562 "\nnet ads printer search <printer>"
1563 "\n\tsearch for a printer in the directory\n"
1564 "\nnet ads printer info <printer> <server>"
1565 "\n\tlookup info in directory for printer on server"
1566 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1567 "\nnet ads printer publish <printername>"
1568 "\n\tpublish printer in directory"
1569 "\n\t(note: printer name is required)\n"
1570 "\nnet ads printer remove <printername>"
1571 "\n\tremove printer from directory"
1572 "\n\t(note: printer name is required)\n");
1576 /*******************************************************************
1577 ********************************************************************/
1579 static int net_ads_printer_search(int argc, const char **argv)
1583 LDAPMessage *res = NULL;
1585 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1589 rc = ads_find_printers(ads, &res);
1591 if (!ADS_ERR_OK(rc)) {
1592 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1593 ads_msgfree(ads, res);
1598 if (ads_count_replies(ads, res) == 0) {
1599 d_fprintf(stderr, "No results found\n");
1600 ads_msgfree(ads, res);
1606 ads_msgfree(ads, res);
1611 static int net_ads_printer_info(int argc, const char **argv)
1615 const char *servername, *printername;
1616 LDAPMessage *res = NULL;
1618 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1623 printername = argv[0];
1629 servername = argv[1];
1631 servername = global_myname();
1634 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1636 if (!ADS_ERR_OK(rc)) {
1637 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1638 ads_msgfree(ads, res);
1643 if (ads_count_replies(ads, res) == 0) {
1644 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1645 ads_msgfree(ads, res);
1651 ads_msgfree(ads, res);
1657 void do_drv_upgrade_printer(int msg_type, struct process_id src,
1658 void *buf, size_t len)
1663 static int net_ads_printer_publish(int argc, const char **argv)
1667 const char *servername, *printername;
1668 struct cli_state *cli;
1669 struct rpc_pipe_client *pipe_hnd;
1670 struct in_addr server_ip;
1672 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1673 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1674 char *prt_dn, *srv_dn, **srv_cn;
1675 LDAPMessage *res = NULL;
1677 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1682 return net_ads_printer_usage(argc, argv);
1685 printername = argv[0];
1688 servername = argv[1];
1690 servername = global_myname();
1693 /* Get printer data from SPOOLSS */
1695 resolve_name(servername, &server_ip, 0x20);
1697 nt_status = cli_full_connection(&cli, global_myname(), servername,
1700 opt_user_name, opt_workgroup,
1701 opt_password ? opt_password : "",
1702 CLI_FULL_CONNECTION_USE_KERBEROS,
1705 if (NT_STATUS_IS_ERR(nt_status)) {
1706 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1707 "for %s\n", servername, printername);
1712 /* Publish on AD server */
1714 ads_find_machine_acct(ads, &res, servername);
1716 if (ads_count_replies(ads, res) == 0) {
1717 d_fprintf(stderr, "Could not find machine account for server %s\n",
1723 srv_dn = ldap_get_dn((LDAP *)ads->ld, (LDAPMessage *)res);
1724 srv_cn = ldap_explode_dn(srv_dn, 1);
1726 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
1728 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1730 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1736 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1742 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1743 if (!ADS_ERR_OK(rc)) {
1744 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1749 d_printf("published printer\n");
1755 static int net_ads_printer_remove(int argc, const char **argv)
1759 const char *servername;
1761 LDAPMessage *res = NULL;
1763 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1768 return net_ads_printer_usage(argc, argv);
1772 servername = argv[1];
1774 servername = global_myname();
1777 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1779 if (!ADS_ERR_OK(rc)) {
1780 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1781 ads_msgfree(ads, res);
1786 if (ads_count_replies(ads, res) == 0) {
1787 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1788 ads_msgfree(ads, res);
1793 prt_dn = ads_get_dn(ads, res);
1794 ads_msgfree(ads, res);
1795 rc = ads_del_dn(ads, prt_dn);
1796 ads_memfree(ads, prt_dn);
1798 if (!ADS_ERR_OK(rc)) {
1799 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1808 static int net_ads_printer(int argc, const char **argv)
1810 struct functable func[] = {
1811 {"SEARCH", net_ads_printer_search},
1812 {"INFO", net_ads_printer_info},
1813 {"PUBLISH", net_ads_printer_publish},
1814 {"REMOVE", net_ads_printer_remove},
1818 return net_run_function(argc, argv, func, net_ads_printer_usage);
1822 static int net_ads_password(int argc, const char **argv)
1825 const char *auth_principal = opt_user_name;
1826 const char *auth_password = opt_password;
1828 char *new_password = NULL;
1833 if (opt_user_name == NULL || opt_password == NULL) {
1834 d_fprintf(stderr, "You must supply an administrator username/password\n");
1839 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1844 if (!strchr_m(user, '@')) {
1845 asprintf(&c, "%s@%s", argv[0], lp_realm());
1849 use_in_memory_ccache();
1850 c = strchr_m(auth_principal, '@');
1857 /* use the realm so we can eventually change passwords for users
1858 in realms other than default */
1859 if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
1863 /* we don't actually need a full connect, but it's the easy way to
1864 fill in the KDC's addresss */
1867 if (!ads || !ads->config.realm) {
1868 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1873 new_password = (char *)argv[1];
1875 asprintf(&prompt, "Enter new password for %s:", user);
1876 new_password = getpass(prompt);
1880 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1881 auth_password, user, new_password, ads->auth.time_offset);
1882 if (!ADS_ERR_OK(ret)) {
1883 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1888 d_printf("Password change for %s completed.\n", user);
1894 int net_ads_changetrustpw(int argc, const char **argv)
1897 char *host_principal;
1901 if (!secrets_init()) {
1902 DEBUG(1,("Failed to initialise secrets database\n"));
1906 net_use_machine_password();
1908 use_in_memory_ccache();
1910 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1914 fstrcpy(my_name, global_myname());
1915 strlower_m(my_name);
1916 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1917 d_printf("Changing password for principal: %s\n", host_principal);
1919 ret = ads_change_trust_account_password(ads, host_principal);
1921 if (!ADS_ERR_OK(ret)) {
1922 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1924 SAFE_FREE(host_principal);
1928 d_printf("Password change for principal %s succeeded.\n", host_principal);
1930 if (lp_use_kerberos_keytab()) {
1931 d_printf("Attempting to update system keytab with new password.\n");
1932 if (ads_keytab_create_default(ads)) {
1933 d_printf("Failed to update system keytab.\n");
1938 SAFE_FREE(host_principal);
1944 help for net ads search
1946 static int net_ads_search_usage(int argc, const char **argv)
1949 "\nnet ads search <expression> <attributes...>\n"\
1950 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1951 "The expression is a standard LDAP search expression, and the\n"\
1952 "attributes are a list of LDAP fields to show in the results\n\n"\
1953 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1955 net_common_flags_usage(argc, argv);
1961 general ADS search function. Useful in diagnosing problems in ADS
1963 static int net_ads_search(int argc, const char **argv)
1967 const char *ldap_exp;
1969 LDAPMessage *res = NULL;
1972 return net_ads_search_usage(argc, argv);
1975 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1982 rc = ads_do_search_all(ads, ads->config.bind_path,
1984 ldap_exp, attrs, &res);
1985 if (!ADS_ERR_OK(rc)) {
1986 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1991 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1993 /* dump the results */
1996 ads_msgfree(ads, res);
2004 help for net ads search
2006 static int net_ads_dn_usage(int argc, const char **argv)
2009 "\nnet ads dn <dn> <attributes...>\n"\
2010 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2011 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
2012 "to show in the results\n\n"\
2013 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2015 net_common_flags_usage(argc, argv);
2021 general ADS search function. Useful in diagnosing problems in ADS
2023 static int net_ads_dn(int argc, const char **argv)
2029 LDAPMessage *res = NULL;
2032 return net_ads_dn_usage(argc, argv);
2035 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2042 rc = ads_do_search_all(ads, dn,
2044 "(objectclass=*)", attrs, &res);
2045 if (!ADS_ERR_OK(rc)) {
2046 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2051 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2053 /* dump the results */
2056 ads_msgfree(ads, res);
2063 help for net ads sid search
2065 static int net_ads_sid_usage(int argc, const char **argv)
2068 "\nnet ads sid <sid> <attributes...>\n"\
2069 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2070 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
2071 "to show in the results\n\n"\
2072 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2074 net_common_flags_usage(argc, argv);
2080 general ADS search function. Useful in diagnosing problems in ADS
2082 static int net_ads_sid(int argc, const char **argv)
2086 const char *sid_string;
2088 LDAPMessage *res = NULL;
2092 return net_ads_sid_usage(argc, argv);
2095 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2099 sid_string = argv[0];
2102 if (!string_to_sid(&sid, sid_string)) {
2103 d_fprintf(stderr, "could not convert sid\n");
2108 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2109 if (!ADS_ERR_OK(rc)) {
2110 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2115 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2117 /* dump the results */
2120 ads_msgfree(ads, res);
2127 static int net_ads_keytab_usage(int argc, const char **argv)
2130 "net ads keytab <COMMAND>\n"\
2131 "<COMMAND> can be either:\n"\
2132 " CREATE Creates a fresh keytab\n"\
2133 " ADD Adds new service principal\n"\
2134 " FLUSH Flushes out all keytab entries\n"\
2135 " HELP Prints this help message\n"\
2136 "The ADD command will take arguments, the other commands\n"\
2137 "will not take any arguments. The arguments given to ADD\n"\
2138 "should be a list of principals to add. For example, \n"\
2139 " net ads keytab add srv1 srv2\n"\
2140 "will add principals for the services srv1 and srv2 to the\n"\
2141 "system's keytab.\n"\
2147 static int net_ads_keytab_flush(int argc, const char **argv)
2152 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2155 ret = ads_keytab_flush(ads);
2160 static int net_ads_keytab_add(int argc, const char **argv)
2166 d_printf("Processing principals to add...\n");
2167 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2170 for (i = 0; i < argc; i++) {
2171 ret |= ads_keytab_add_entry(ads, argv[i]);
2177 static int net_ads_keytab_create(int argc, const char **argv)
2182 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2185 ret = ads_keytab_create_default(ads);
2190 int net_ads_keytab(int argc, const char **argv)
2192 struct functable func[] = {
2193 {"CREATE", net_ads_keytab_create},
2194 {"ADD", net_ads_keytab_add},
2195 {"FLUSH", net_ads_keytab_flush},
2196 {"HELP", net_ads_keytab_usage},
2200 if (!lp_use_kerberos_keytab()) {
2201 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2202 use keytab functions.\n");
2205 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2208 int net_ads_help(int argc, const char **argv)
2210 struct functable func[] = {
2211 {"USER", net_ads_user_usage},
2212 {"GROUP", net_ads_group_usage},
2213 {"PRINTER", net_ads_printer_usage},
2214 {"SEARCH", net_ads_search_usage},
2215 {"INFO", net_ads_info},
2216 {"JOIN", net_ads_join_usage},
2217 {"DNS", net_ads_dns_usage},
2218 {"LEAVE", net_ads_leave},
2219 {"STATUS", net_ads_status},
2220 {"PASSWORD", net_ads_password},
2221 {"CHANGETRUSTPW", net_ads_changetrustpw},
2225 return net_run_function(argc, argv, func, net_ads_usage);
2228 int net_ads(int argc, const char **argv)
2230 struct functable func[] = {
2231 {"INFO", net_ads_info},
2232 {"JOIN", net_ads_join},
2233 {"TESTJOIN", net_ads_testjoin},
2234 {"LEAVE", net_ads_leave},
2235 {"STATUS", net_ads_status},
2236 {"USER", net_ads_user},
2237 {"GROUP", net_ads_group},
2238 {"DNS", net_ads_dns},
2239 {"PASSWORD", net_ads_password},
2240 {"CHANGETRUSTPW", net_ads_changetrustpw},
2241 {"PRINTER", net_ads_printer},
2242 {"SEARCH", net_ads_search},
2244 {"SID", net_ads_sid},
2245 {"WORKGROUP", net_ads_workgroup},
2246 {"LOOKUP", net_ads_lookup},
2247 {"KEYTAB", net_ads_keytab},
2248 {"GPO", net_ads_gpo},
2249 {"HELP", net_ads_help},
2253 return net_run_function(argc, argv, func, net_ads_usage);
2258 static int net_ads_noads(void)
2260 d_fprintf(stderr, "ADS support not compiled in\n");
2264 int net_ads_keytab(int argc, const char **argv)
2266 return net_ads_noads();
2269 int net_ads_usage(int argc, const char **argv)
2271 return net_ads_noads();
2274 int net_ads_help(int argc, const char **argv)
2276 return net_ads_noads();
2279 int net_ads_changetrustpw(int argc, const char **argv)
2281 return net_ads_noads();
2284 int net_ads_join(int argc, const char **argv)
2286 return net_ads_noads();
2289 int net_ads_user(int argc, const char **argv)
2291 return net_ads_noads();
2294 int net_ads_group(int argc, const char **argv)
2296 return net_ads_noads();
2299 /* this one shouldn't display a message */
2300 int net_ads_check(void)
2305 int net_ads_check_our_domain(void)
2310 int net_ads(int argc, const char **argv)
2312 return net_ads_usage(argc, argv);
2315 #endif /* WITH_ADS */