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 cldap_netlogon_reply reply
;
87 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
88 if ( !ads_cldap_netlogon(addr
, ads
->server
.realm
, &reply
) ) {
89 d_fprintf(stderr
, "CLDAP query failed!\n");
93 d_printf("Information for Domain Controller: %s\n\n",
96 d_printf("Response Type: ");
98 case SAMLOGON_AD_UNK_R
:
99 d_printf("SAMLOGON\n");
102 d_printf("SAMLOGON_USER\n");
105 d_printf("0x%x\n", reply
.type
);
109 smb_uuid_unpack(reply
.guid
, &tmp_guid
);
110 d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), tmp_guid
));
114 "\tIs a GC of the forest: %s\n"
115 "\tIs an LDAP server: %s\n"
116 "\tSupports DS: %s\n"
117 "\tIs running a KDC: %s\n"
118 "\tIs running time services: %s\n"
119 "\tIs the closest DC: %s\n"
120 "\tIs writable: %s\n"
121 "\tHas a hardware clock: %s\n"
122 "\tIs a non-domain NC serviced by LDAP server: %s\n",
123 (reply
.flags
& ADS_PDC
) ? "yes" : "no",
124 (reply
.flags
& ADS_GC
) ? "yes" : "no",
125 (reply
.flags
& ADS_LDAP
) ? "yes" : "no",
126 (reply
.flags
& ADS_DS
) ? "yes" : "no",
127 (reply
.flags
& ADS_KDC
) ? "yes" : "no",
128 (reply
.flags
& ADS_TIMESERV
) ? "yes" : "no",
129 (reply
.flags
& ADS_CLOSEST
) ? "yes" : "no",
130 (reply
.flags
& ADS_WRITABLE
) ? "yes" : "no",
131 (reply
.flags
& ADS_GOOD_TIMESERV
) ? "yes" : "no",
132 (reply
.flags
& ADS_NDNC
) ? "yes" : "no");
134 printf("Forest:\t\t\t%s\n", reply
.forest
);
135 printf("Domain:\t\t\t%s\n", reply
.domain
);
136 printf("Domain Controller:\t%s\n", reply
.hostname
);
138 printf("Pre-Win2k Domain:\t%s\n", reply
.netbios_domain
);
139 printf("Pre-Win2k Hostname:\t%s\n", reply
.netbios_hostname
);
141 if (*reply
.unk
) printf("Unk:\t\t\t%s\n", reply
.unk
);
142 if (*reply
.user_name
) printf("User name:\t%s\n", reply
.user_name
);
144 printf("Server Site Name :\t\t%s\n", reply
.server_site_name
);
145 printf("Client Site Name :\t\t%s\n", reply
.client_site_name
);
147 d_printf("NT Version: %d\n", reply
.version
);
148 d_printf("LMNT Token: %.2x\n", reply
.lmnt_token
);
149 d_printf("LM20 Token: %.2x\n", reply
.lm20_token
);
155 this implements the CLDAP based netlogon lookup requests
156 for finding the domain controller of a ADS domain
158 static int net_ads_lookup(int argc
, const char **argv
)
162 if (!ADS_ERR_OK(ads_startup_nobind(False
, &ads
))) {
163 d_fprintf(stderr
, "Didn't find the cldap server!\n");
167 if (!ads
->config
.realm
) {
168 ads
->config
.realm
= CONST_DISCARD(char *, opt_target_workgroup
);
169 ads
->ldap
.port
= 389;
172 return net_ads_cldap_netlogon(ads
);
177 static int net_ads_info(int argc
, const char **argv
)
180 char addr
[INET6_ADDRSTRLEN
];
182 if (!ADS_ERR_OK(ads_startup_nobind(False
, &ads
))) {
183 d_fprintf(stderr
, "Didn't find the ldap server!\n");
187 if (!ads
|| !ads
->config
.realm
) {
188 d_fprintf(stderr
, "Didn't find the ldap server!\n");
192 /* Try to set the server's current time since we didn't do a full
193 TCP LDAP session initially */
195 if ( !ADS_ERR_OK(ads_current_time( ads
)) ) {
196 d_fprintf( stderr
, "Failed to get server's current time!\n");
199 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
201 d_printf("LDAP server: %s\n", addr
);
202 d_printf("LDAP server name: %s\n", ads
->config
.ldap_server_name
);
203 d_printf("Realm: %s\n", ads
->config
.realm
);
204 d_printf("Bind Path: %s\n", ads
->config
.bind_path
);
205 d_printf("LDAP port: %d\n", ads
->ldap
.port
);
206 d_printf("Server time: %s\n", http_timestring(ads
->config
.current_time
));
208 d_printf("KDC server: %s\n", ads
->auth
.kdc_server
);
209 d_printf("Server time offset: %d\n", ads
->auth
.time_offset
);
214 static void use_in_memory_ccache(void) {
215 /* Use in-memory credentials cache so we do not interfere with
216 * existing credentials */
217 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
220 static ADS_STATUS
ads_startup_int(bool only_own_domain
, uint32 auth_flags
, ADS_STRUCT
**ads_ret
)
222 ADS_STRUCT
*ads
= NULL
;
224 bool need_password
= False
;
225 bool second_time
= False
;
227 const char *realm
= NULL
;
228 bool tried_closest_dc
= False
;
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 */
238 if (only_own_domain
) {
241 realm
= assume_own_realm();
244 ads
= ads_init(realm
, opt_target_workgroup
, opt_host
);
246 if (!opt_user_name
) {
247 opt_user_name
= "administrator";
250 if (opt_user_specified
) {
251 need_password
= True
;
255 if (!opt_password
&& need_password
&& !opt_machine_pass
) {
256 opt_password
= net_prompt_pass(opt_user_name
);
259 return ADS_ERROR(LDAP_NO_MEMORY
);
264 use_in_memory_ccache();
265 SAFE_FREE(ads
->auth
.password
);
266 ads
->auth
.password
= smb_xstrdup(opt_password
);
269 ads
->auth
.flags
|= auth_flags
;
270 SAFE_FREE(ads
->auth
.user_name
);
271 ads
->auth
.user_name
= smb_xstrdup(opt_user_name
);
274 * If the username is of the form "name@realm",
275 * extract the realm and convert to upper case.
276 * This is only used to establish the connection.
278 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
280 SAFE_FREE(ads
->auth
.realm
);
281 ads
->auth
.realm
= smb_xstrdup(cp
);
282 strupper_m(ads
->auth
.realm
);
285 status
= ads_connect(ads
);
287 if (!ADS_ERR_OK(status
)) {
289 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
290 NT_STATUS_NO_LOGON_SERVERS
)) {
291 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
296 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
297 need_password
= True
;
306 /* when contacting our own domain, make sure we use the closest DC.
307 * This is done by reconnecting to ADS because only the first call to
308 * ads_connect will give us our own sitename */
310 if ((only_own_domain
|| !opt_host
) && !tried_closest_dc
) {
312 tried_closest_dc
= True
; /* avoid loop */
314 if (!ads
->config
.tried_closest_dc
) {
316 namecache_delete(ads
->server
.realm
, 0x1C);
317 namecache_delete(ads
->server
.workgroup
, 0x1C);
330 ADS_STATUS
ads_startup(bool only_own_domain
, ADS_STRUCT
**ads
)
332 return ads_startup_int(only_own_domain
, 0, ads
);
335 ADS_STATUS
ads_startup_nobind(bool only_own_domain
, ADS_STRUCT
**ads
)
337 return ads_startup_int(only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
341 Check to see if connection can be made via ads.
342 ads_startup() stores the password in opt_password if it needs to so
343 that rpc or rap can use it without re-prompting.
345 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
350 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
354 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
356 status
= ads_connect(ads
);
357 if ( !ADS_ERR_OK(status
) ) {
365 int net_ads_check_our_domain(void)
367 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
370 int net_ads_check(void)
372 return net_ads_check_int(NULL
, opt_workgroup
, opt_host
);
376 determine the netbios workgroup name for a domain
378 static int net_ads_workgroup(int argc
, const char **argv
)
381 char addr
[INET6_ADDRSTRLEN
];
382 struct cldap_netlogon_reply reply
;
384 if (!ADS_ERR_OK(ads_startup_nobind(False
, &ads
))) {
385 d_fprintf(stderr
, "Didn't find the cldap server!\n");
389 if (!ads
->config
.realm
) {
390 ads
->config
.realm
= CONST_DISCARD(char *, opt_target_workgroup
);
391 ads
->ldap
.port
= 389;
394 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
395 if ( !ads_cldap_netlogon(addr
, ads
->server
.realm
, &reply
) ) {
396 d_fprintf(stderr
, "CLDAP query failed!\n");
400 d_printf("Workgroup: %s\n", reply
.netbios_domain
);
409 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
411 char **disp_fields
= (char **) data_area
;
413 if (!field
) { /* must be end of record */
414 if (disp_fields
[0]) {
415 if (!strchr_m(disp_fields
[0], '$')) {
417 d_printf("%-21.21s %s\n",
418 disp_fields
[0], disp_fields
[1]);
420 d_printf("%s\n", disp_fields
[0]);
423 SAFE_FREE(disp_fields
[0]);
424 SAFE_FREE(disp_fields
[1]);
427 if (!values
) /* must be new field, indicate string field */
429 if (StrCaseCmp(field
, "sAMAccountName") == 0) {
430 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
432 if (StrCaseCmp(field
, "description") == 0)
433 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
437 static int net_ads_user_usage(int argc
, const char **argv
)
439 return net_help_user(argc
, argv
);
442 static int ads_user_add(int argc
, const char **argv
)
447 LDAPMessage
*res
=NULL
;
451 if (argc
< 1) return net_ads_user_usage(argc
, argv
);
453 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
457 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
459 if (!ADS_ERR_OK(status
)) {
460 d_fprintf(stderr
, "ads_user_add: %s\n", ads_errstr(status
));
464 if (ads_count_replies(ads
, res
)) {
465 d_fprintf(stderr
, "ads_user_add: User %s already exists\n", argv
[0]);
470 ou_str
= SMB_STRDUP(opt_container
);
472 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
475 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, opt_comment
);
477 if (!ADS_ERR_OK(status
)) {
478 d_fprintf(stderr
, "Could not add user %s: %s\n", argv
[0],
483 /* if no password is to be set, we're done */
485 d_printf("User %s added\n", argv
[0]);
490 /* try setting the password */
491 asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
);
492 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
493 ads
->auth
.time_offset
);
495 if (ADS_ERR_OK(status
)) {
496 d_printf("User %s added\n", argv
[0]);
501 /* password didn't set, delete account */
502 d_fprintf(stderr
, "Could not add user %s. Error setting password %s\n",
503 argv
[0], ads_errstr(status
));
504 ads_msgfree(ads
, res
);
505 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
506 if (ADS_ERR_OK(status
)) {
507 userdn
= ads_get_dn(ads
, res
);
508 ads_del_dn(ads
, userdn
);
509 ads_memfree(ads
, userdn
);
514 ads_msgfree(ads
, res
);
520 static int ads_user_info(int argc
, const char **argv
)
525 const char *attrs
[] = {"memberOf", NULL
};
526 char *searchstring
=NULL
;
531 return net_ads_user_usage(argc
, argv
);
534 escaped_user
= escape_ldap_string_alloc(argv
[0]);
537 d_fprintf(stderr
, "ads_user_info: failed to escape user %s\n", argv
[0]);
541 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
542 SAFE_FREE(escaped_user
);
546 asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
);
547 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
548 safe_free(searchstring
);
550 if (!ADS_ERR_OK(rc
)) {
551 d_fprintf(stderr
, "ads_search: %s\n", ads_errstr(rc
));
553 SAFE_FREE(escaped_user
);
557 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
558 (LDAPMessage
*)res
, "memberOf");
563 for (i
=0;grouplist
[i
];i
++) {
564 groupname
= ldap_explode_dn(grouplist
[i
], 1);
565 d_printf("%s\n", groupname
[0]);
566 ldap_value_free(groupname
);
568 ldap_value_free(grouplist
);
571 ads_msgfree(ads
, res
);
573 SAFE_FREE(escaped_user
);
577 static int ads_user_delete(int argc
, const char **argv
)
581 LDAPMessage
*res
= NULL
;
585 return net_ads_user_usage(argc
, argv
);
588 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
592 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
593 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
594 d_printf("User %s does not exist.\n", argv
[0]);
595 ads_msgfree(ads
, res
);
599 userdn
= ads_get_dn(ads
, res
);
600 ads_msgfree(ads
, res
);
601 rc
= ads_del_dn(ads
, userdn
);
602 ads_memfree(ads
, userdn
);
603 if (ADS_ERR_OK(rc
)) {
604 d_printf("User %s deleted\n", argv
[0]);
608 d_fprintf(stderr
, "Error deleting user %s: %s\n", argv
[0],
614 int net_ads_user(int argc
, const char **argv
)
616 struct functable func
[] = {
617 {"ADD", ads_user_add
},
618 {"INFO", ads_user_info
},
619 {"DELETE", ads_user_delete
},
624 const char *shortattrs
[] = {"sAMAccountName", NULL
};
625 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
626 char *disp_fields
[2] = {NULL
, NULL
};
629 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
633 if (opt_long_list_entries
)
634 d_printf("\nUser name Comment"\
635 "\n-----------------------------\n");
637 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
639 "(objectCategory=user)",
640 opt_long_list_entries
? longattrs
:
641 shortattrs
, usergrp_display
,
644 return ADS_ERR_OK(rc
) ? 0 : -1;
647 return net_run_function(argc
, argv
, func
, net_ads_user_usage
);
650 static int net_ads_group_usage(int argc
, const char **argv
)
652 return net_help_group(argc
, argv
);
655 static int ads_group_add(int argc
, const char **argv
)
659 LDAPMessage
*res
=NULL
;
664 return net_ads_group_usage(argc
, argv
);
667 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
671 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
673 if (!ADS_ERR_OK(status
)) {
674 d_fprintf(stderr
, "ads_group_add: %s\n", ads_errstr(status
));
678 if (ads_count_replies(ads
, res
)) {
679 d_fprintf(stderr
, "ads_group_add: Group %s already exists\n", argv
[0]);
684 ou_str
= SMB_STRDUP(opt_container
);
686 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
689 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, opt_comment
);
691 if (ADS_ERR_OK(status
)) {
692 d_printf("Group %s added\n", argv
[0]);
695 d_fprintf(stderr
, "Could not add group %s: %s\n", argv
[0],
701 ads_msgfree(ads
, res
);
707 static int ads_group_delete(int argc
, const char **argv
)
711 LDAPMessage
*res
= NULL
;
715 return net_ads_group_usage(argc
, argv
);
718 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
722 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
723 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
724 d_printf("Group %s does not exist.\n", argv
[0]);
725 ads_msgfree(ads
, res
);
729 groupdn
= ads_get_dn(ads
, res
);
730 ads_msgfree(ads
, res
);
731 rc
= ads_del_dn(ads
, groupdn
);
732 ads_memfree(ads
, groupdn
);
733 if (ADS_ERR_OK(rc
)) {
734 d_printf("Group %s deleted\n", argv
[0]);
738 d_fprintf(stderr
, "Error deleting group %s: %s\n", argv
[0],
744 int net_ads_group(int argc
, const char **argv
)
746 struct functable func
[] = {
747 {"ADD", ads_group_add
},
748 {"DELETE", ads_group_delete
},
753 const char *shortattrs
[] = {"sAMAccountName", NULL
};
754 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
755 char *disp_fields
[2] = {NULL
, NULL
};
758 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
762 if (opt_long_list_entries
)
763 d_printf("\nGroup name Comment"\
764 "\n-----------------------------\n");
765 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
767 "(objectCategory=group)",
768 opt_long_list_entries
? longattrs
:
769 shortattrs
, usergrp_display
,
773 return ADS_ERR_OK(rc
) ? 0 : -1;
775 return net_run_function(argc
, argv
, func
, net_ads_group_usage
);
778 static int net_ads_status(int argc
, const char **argv
)
784 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
788 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
789 if (!ADS_ERR_OK(rc
)) {
790 d_fprintf(stderr
, "ads_find_machine_acct: %s\n", ads_errstr(rc
));
795 if (ads_count_replies(ads
, res
) == 0) {
796 d_fprintf(stderr
, "No machine account for '%s' found\n", global_myname());
806 /*******************************************************************
807 Leave an AD domain. Windows XP disables the machine account.
808 We'll try the same. The old code would do an LDAP delete.
809 That only worked using the machine creds because added the machine
810 with full control to the computer object's ACL.
811 *******************************************************************/
813 static int net_ads_leave(int argc
, const char **argv
)
816 struct libnet_UnjoinCtx
*r
= NULL
;
820 d_fprintf(stderr
, "No realm set, are we joined ?\n");
824 if (!(ctx
= talloc_init("net_ads_leave"))) {
825 d_fprintf(stderr
, "Could not initialise talloc context.\n");
829 use_in_memory_ccache();
831 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
832 if (!W_ERROR_IS_OK(werr
)) {
833 d_fprintf(stderr
, "Could not initialise unjoin context.\n");
838 r
->in
.dc_name
= opt_host
;
839 r
->in
.domain_name
= lp_realm();
840 r
->in
.admin_account
= opt_user_name
;
841 r
->in
.admin_password
= net_prompt_pass(opt_user_name
);
842 r
->in
.modify_config
= lp_config_backend_is_registry();
843 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
844 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
846 werr
= libnet_Unjoin(ctx
, r
);
847 if (!W_ERROR_IS_OK(werr
)) {
848 d_printf("Failed to leave domain: %s\n",
849 r
->out
.error_string
? r
->out
.error_string
:
850 get_friendly_werror_msg(werr
));
854 if (W_ERROR_IS_OK(werr
)) {
855 d_printf("Deleted account for '%s' in realm '%s'\n",
856 r
->in
.machine_name
, r
->out
.dns_domain_name
);
860 /* We couldn't delete it - see if the disable succeeded. */
861 if (r
->out
.disabled_machine_account
) {
862 d_printf("Disabled account for '%s' in realm '%s'\n",
863 r
->in
.machine_name
, r
->out
.dns_domain_name
);
868 d_fprintf(stderr
, "Failed to disable machine account for '%s' in realm '%s'\n",
869 r
->in
.machine_name
, r
->out
.dns_domain_name
);
875 if (W_ERROR_IS_OK(werr
)) {
882 static NTSTATUS
net_ads_join_ok(void)
884 ADS_STRUCT
*ads
= NULL
;
887 if (!secrets_init()) {
888 DEBUG(1,("Failed to initialise secrets database\n"));
889 return NT_STATUS_ACCESS_DENIED
;
892 net_use_krb_machine_account();
894 status
= ads_startup(True
, &ads
);
895 if (!ADS_ERR_OK(status
)) {
896 return ads_ntstatus(status
);
904 check that an existing join is OK
906 int net_ads_testjoin(int argc
, const char **argv
)
909 use_in_memory_ccache();
911 /* Display success or failure */
912 status
= net_ads_join_ok();
913 if (!NT_STATUS_IS_OK(status
)) {
914 fprintf(stderr
,"Join to domain is not valid: %s\n",
915 get_friendly_nt_error_msg(status
));
919 printf("Join is OK\n");
923 /*******************************************************************
924 Simple configu checks before beginning the join
925 ********************************************************************/
927 static WERROR
check_ads_config( void )
929 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
930 d_printf("Host is not configured as a member server.\n");
931 return WERR_INVALID_DOMAIN_ROLE
;
934 if (strlen(global_myname()) > 15) {
935 d_printf("Our netbios name can be at most 15 chars long, "
936 "\"%s\" is %u chars long\n", global_myname(),
937 (unsigned int)strlen(global_myname()));
938 return WERR_INVALID_COMPUTER_NAME
;
941 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
942 d_fprintf(stderr
, "realm must be set in in %s for ADS "
943 "join to succeed.\n", get_dyn_CONFIGFILE());
944 return WERR_INVALID_PARAM
;
950 /*******************************************************************
951 Send a DNS update request
952 *******************************************************************/
954 #if defined(WITH_DNS_UPDATES)
956 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
957 const char *pszDomainName
, const char *pszHostName
,
958 const struct sockaddr_storage
*sslist
,
961 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
962 const char *machine_name
,
963 const struct sockaddr_storage
*addrs
,
966 struct dns_rr_ns
*nameservers
= NULL
;
968 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
971 const char *dnsdomain
= NULL
;
972 char *root_domain
= NULL
;
974 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
975 d_printf("No DNS domain configured for %s. "
976 "Unable to perform DNS Update.\n", machine_name
);
977 status
= NT_STATUS_INVALID_PARAMETER
;
982 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
983 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
984 /* Child domains often do not have NS records. Look
985 for the NS record for the forest root domain
986 (rootDomainNamingContext in therootDSE) */
988 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
989 LDAPMessage
*msg
= NULL
;
991 ADS_STATUS ads_status
;
993 if ( !ads
->ldap
.ld
) {
994 ads_status
= ads_connect( ads
);
995 if ( !ADS_ERR_OK(ads_status
) ) {
996 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1001 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1002 "(objectclass=*)", rootname_attrs
, &msg
);
1003 if (!ADS_ERR_OK(ads_status
)) {
1007 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1009 ads_msgfree( ads
, msg
);
1013 root_domain
= ads_build_domain( root_dn
);
1016 ads_msgfree( ads
, msg
);
1018 /* try again for NS servers */
1020 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1022 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1023 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1024 "realm\n", ads
->config
.realm
));
1028 dnsdomain
= root_domain
;
1032 /* Now perform the dns update - we'll try non-secure and if we fail,
1033 we'll follow it up with a secure update */
1035 fstrcpy( dns_server
, nameservers
[0].hostname
);
1037 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1038 if (!ERR_DNS_IS_OK(dns_err
)) {
1039 status
= NT_STATUS_UNSUCCESSFUL
;
1044 SAFE_FREE( root_domain
);
1049 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
)
1052 struct sockaddr_storage
*iplist
= NULL
;
1053 fstring machine_name
;
1056 name_to_fqdn( machine_name
, global_myname() );
1057 strlower_m( machine_name
);
1059 /* Get our ip address (not the 127.0.0.x address but a real ip
1062 num_addrs
= get_my_ip_address( &iplist
);
1063 if ( num_addrs
<= 0 ) {
1064 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1066 return NT_STATUS_INVALID_PARAMETER
;
1069 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1071 SAFE_FREE( iplist
);
1077 /*******************************************************************
1078 ********************************************************************/
1080 static int net_ads_join_usage(int argc
, const char **argv
)
1082 d_printf("net ads join [options]\n");
1083 d_printf("Valid options:\n");
1084 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1085 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1086 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1087 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1088 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1089 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1090 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1091 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1092 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1093 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1094 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1095 d_printf(" the two other attributes.\n");
1100 /*******************************************************************
1101 ********************************************************************/
1103 int net_ads_join(int argc
, const char **argv
)
1105 TALLOC_CTX
*ctx
= NULL
;
1106 struct libnet_JoinCtx
*r
= NULL
;
1107 const char *domain
= lp_realm();
1108 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1109 bool createupn
= False
;
1110 const char *machineupn
= NULL
;
1111 const char *create_in_ou
= NULL
;
1113 const char *os_name
= NULL
;
1114 const char *os_version
= NULL
;
1115 bool modify_config
= lp_config_backend_is_registry();
1117 if (!modify_config
) {
1119 werr
= check_ads_config();
1120 if (!W_ERROR_IS_OK(werr
)) {
1121 d_fprintf(stderr
, "Invalid configuration. Exiting....\n");
1126 if (!(ctx
= talloc_init("net_ads_join"))) {
1127 d_fprintf(stderr
, "Could not initialise talloc context.\n");
1132 use_in_memory_ccache();
1134 werr
= libnet_init_JoinCtx(ctx
, &r
);
1135 if (!W_ERROR_IS_OK(werr
)) {
1139 /* process additional command line args */
1141 for ( i
=0; i
<argc
; i
++ ) {
1142 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1144 machineupn
= get_string_param(argv
[i
]);
1146 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1147 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1148 d_fprintf(stderr
, "Please supply a valid OU path.\n");
1149 werr
= WERR_INVALID_PARAM
;
1153 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1154 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1155 d_fprintf(stderr
, "Please supply a operating system name.\n");
1156 werr
= WERR_INVALID_PARAM
;
1160 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1161 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1162 d_fprintf(stderr
, "Please supply a valid operating system version.\n");
1163 werr
= WERR_INVALID_PARAM
;
1173 d_fprintf(stderr
, "Please supply a valid domain name\n");
1174 werr
= WERR_INVALID_PARAM
;
1178 /* Do the domain join here */
1180 r
->in
.domain_name
= domain
;
1181 r
->in
.create_upn
= createupn
;
1182 r
->in
.upn
= machineupn
;
1183 r
->in
.account_ou
= create_in_ou
;
1184 r
->in
.os_name
= os_name
;
1185 r
->in
.os_version
= os_version
;
1186 r
->in
.dc_name
= opt_host
;
1187 r
->in
.admin_account
= opt_user_name
;
1188 r
->in
.admin_password
= net_prompt_pass(opt_user_name
);
1190 r
->in
.modify_config
= modify_config
;
1191 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1192 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1193 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1195 werr
= libnet_Join(ctx
, r
);
1196 if (!W_ERROR_IS_OK(werr
)) {
1200 /* Check the short name of the domain */
1202 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1203 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1204 d_printf("domain name obtained from the server.\n");
1205 d_printf("Using the name [%s] from the server.\n", r
->out
.netbios_domain_name
);
1206 d_printf("You should set \"workgroup = %s\" in %s.\n",
1207 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1210 d_printf("Using short domain name -- %s\n", r
->out
.netbios_domain_name
);
1212 if (r
->out
.dns_domain_name
) {
1213 d_printf("Joined '%s' to realm '%s'\n", r
->in
.machine_name
,
1214 r
->out
.dns_domain_name
);
1216 d_printf("Joined '%s' to domain '%s'\n", r
->in
.machine_name
,
1217 r
->out
.netbios_domain_name
);
1220 #if defined(WITH_DNS_UPDATES)
1221 if (r
->out
.domain_is_ad
) {
1222 /* We enter this block with user creds */
1223 ADS_STRUCT
*ads_dns
= NULL
;
1225 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1226 /* kinit with the machine password */
1228 use_in_memory_ccache();
1229 asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname() );
1230 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1231 r
->out
.netbios_domain_name
, NULL
, NULL
);
1232 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1233 ads_kinit_password( ads_dns
);
1236 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns( ctx
, ads_dns
)) ) {
1237 d_fprintf( stderr
, "DNS update failed!\n" );
1240 /* exit from this block using machine creds */
1241 ads_destroy(&ads_dns
);
1250 /* issue an overall failure message at the end. */
1251 d_printf("Failed to join domain: %s\n",
1252 r
&& r
->out
.error_string
? r
->out
.error_string
:
1253 get_friendly_werror_msg(werr
));
1259 /*******************************************************************
1260 ********************************************************************/
1262 static int net_ads_dns_usage(int argc
, const char **argv
)
1264 #if defined(WITH_DNS_UPDATES)
1265 d_printf("net ads dns <command>\n");
1266 d_printf("Valid commands:\n");
1267 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1271 d_fprintf(stderr
, "DNS update support not enabled at compile time!\n");
1276 /*******************************************************************
1277 ********************************************************************/
1279 static int net_ads_dns_register(int argc
, const char **argv
)
1281 #if defined(WITH_DNS_UPDATES)
1287 talloc_enable_leak_report();
1291 d_fprintf(stderr
, "net ads dns register\n");
1295 if (!(ctx
= talloc_init("net_ads_dns"))) {
1296 d_fprintf(stderr
, "Could not initialise talloc context\n");
1300 status
= ads_startup(True
, &ads
);
1301 if ( !ADS_ERR_OK(status
) ) {
1302 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1307 if ( !NT_STATUS_IS_OK(net_update_dns(ctx
, ads
)) ) {
1308 d_fprintf( stderr
, "DNS update failed!\n" );
1309 ads_destroy( &ads
);
1314 d_fprintf( stderr
, "Successfully registered hostname with DNS\n" );
1321 d_fprintf(stderr
, "DNS update support not enabled at compile time!\n");
1326 #if defined(WITH_DNS_UPDATES)
1327 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1330 static int net_ads_dns_gethostbyname(int argc
, const char **argv
)
1332 #if defined(WITH_DNS_UPDATES)
1336 talloc_enable_leak_report();
1340 d_fprintf(stderr
, "net ads dns gethostbyname <server> "
1345 err
= do_gethostbyname(argv
[0], argv
[1]);
1347 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err
));
1352 static int net_ads_dns(int argc
, const char *argv
[])
1354 struct functable func
[] = {
1355 {"REGISTER", net_ads_dns_register
},
1356 {"GETHOSTBYNAME", net_ads_dns_gethostbyname
},
1360 return net_run_function(argc
, argv
, func
, net_ads_dns_usage
);
1363 /*******************************************************************
1364 ********************************************************************/
1366 int net_ads_printer_usage(int argc
, const char **argv
)
1369 "\nnet ads printer search <printer>"
1370 "\n\tsearch for a printer in the directory\n"
1371 "\nnet ads printer info <printer> <server>"
1372 "\n\tlookup info in directory for printer on server"
1373 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1374 "\nnet ads printer publish <printername>"
1375 "\n\tpublish printer in directory"
1376 "\n\t(note: printer name is required)\n"
1377 "\nnet ads printer remove <printername>"
1378 "\n\tremove printer from directory"
1379 "\n\t(note: printer name is required)\n");
1383 /*******************************************************************
1384 ********************************************************************/
1386 static int net_ads_printer_search(int argc
, const char **argv
)
1390 LDAPMessage
*res
= NULL
;
1392 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
1396 rc
= ads_find_printers(ads
, &res
);
1398 if (!ADS_ERR_OK(rc
)) {
1399 d_fprintf(stderr
, "ads_find_printer: %s\n", ads_errstr(rc
));
1400 ads_msgfree(ads
, res
);
1405 if (ads_count_replies(ads
, res
) == 0) {
1406 d_fprintf(stderr
, "No results found\n");
1407 ads_msgfree(ads
, res
);
1413 ads_msgfree(ads
, res
);
1418 static int net_ads_printer_info(int argc
, const char **argv
)
1422 const char *servername
, *printername
;
1423 LDAPMessage
*res
= NULL
;
1425 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
1430 printername
= argv
[0];
1436 servername
= argv
[1];
1438 servername
= global_myname();
1441 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1443 if (!ADS_ERR_OK(rc
)) {
1444 d_fprintf(stderr
, "Server '%s' not found: %s\n",
1445 servername
, ads_errstr(rc
));
1446 ads_msgfree(ads
, res
);
1451 if (ads_count_replies(ads
, res
) == 0) {
1452 d_fprintf(stderr
, "Printer '%s' not found\n", printername
);
1453 ads_msgfree(ads
, res
);
1459 ads_msgfree(ads
, res
);
1465 static int net_ads_printer_publish(int argc
, const char **argv
)
1469 const char *servername
, *printername
;
1470 struct cli_state
*cli
;
1471 struct rpc_pipe_client
*pipe_hnd
;
1472 struct sockaddr_storage server_ss
;
1474 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1475 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1476 char *prt_dn
, *srv_dn
, **srv_cn
;
1477 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1478 LDAPMessage
*res
= NULL
;
1480 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
1481 talloc_destroy(mem_ctx
);
1486 talloc_destroy(mem_ctx
);
1487 return net_ads_printer_usage(argc
, argv
);
1490 printername
= argv
[0];
1493 servername
= argv
[1];
1495 servername
= global_myname();
1498 /* Get printer data from SPOOLSS */
1500 resolve_name(servername
, &server_ss
, 0x20);
1502 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1505 opt_user_name
, opt_workgroup
,
1506 opt_password
? opt_password
: "",
1507 CLI_FULL_CONNECTION_USE_KERBEROS
,
1510 if (NT_STATUS_IS_ERR(nt_status
)) {
1511 d_fprintf(stderr
, "Unable to open a connnection to %s to obtain data "
1512 "for %s\n", servername
, printername
);
1514 talloc_destroy(mem_ctx
);
1518 /* Publish on AD server */
1520 ads_find_machine_acct(ads
, &res
, servername
);
1522 if (ads_count_replies(ads
, res
) == 0) {
1523 d_fprintf(stderr
, "Could not find machine account for server %s\n",
1526 talloc_destroy(mem_ctx
);
1530 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1531 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1533 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1534 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1535 if (!srv_cn_escaped
|| !printername_escaped
) {
1536 SAFE_FREE(srv_cn_escaped
);
1537 SAFE_FREE(printername_escaped
);
1538 d_fprintf(stderr
, "Internal error, out of memory!");
1540 talloc_destroy(mem_ctx
);
1544 asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
);
1546 SAFE_FREE(srv_cn_escaped
);
1547 SAFE_FREE(printername_escaped
);
1549 pipe_hnd
= cli_rpc_pipe_open_noauth(cli
, PI_SPOOLSS
, &nt_status
);
1551 d_fprintf(stderr
, "Unable to open a connnection to the spoolss pipe on %s\n",
1555 talloc_destroy(mem_ctx
);
1559 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1563 talloc_destroy(mem_ctx
);
1567 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1568 if (!ADS_ERR_OK(rc
)) {
1569 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1572 talloc_destroy(mem_ctx
);
1576 d_printf("published printer\n");
1579 talloc_destroy(mem_ctx
);
1584 static int net_ads_printer_remove(int argc
, const char **argv
)
1588 const char *servername
;
1590 LDAPMessage
*res
= NULL
;
1592 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
1597 return net_ads_printer_usage(argc
, argv
);
1601 servername
= argv
[1];
1603 servername
= global_myname();
1606 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1608 if (!ADS_ERR_OK(rc
)) {
1609 d_fprintf(stderr
, "ads_find_printer_on_server: %s\n", ads_errstr(rc
));
1610 ads_msgfree(ads
, res
);
1615 if (ads_count_replies(ads
, res
) == 0) {
1616 d_fprintf(stderr
, "Printer '%s' not found\n", argv
[1]);
1617 ads_msgfree(ads
, res
);
1622 prt_dn
= ads_get_dn(ads
, res
);
1623 ads_msgfree(ads
, res
);
1624 rc
= ads_del_dn(ads
, prt_dn
);
1625 ads_memfree(ads
, prt_dn
);
1627 if (!ADS_ERR_OK(rc
)) {
1628 d_fprintf(stderr
, "ads_del_dn: %s\n", ads_errstr(rc
));
1637 static int net_ads_printer(int argc
, const char **argv
)
1639 struct functable func
[] = {
1640 {"SEARCH", net_ads_printer_search
},
1641 {"INFO", net_ads_printer_info
},
1642 {"PUBLISH", net_ads_printer_publish
},
1643 {"REMOVE", net_ads_printer_remove
},
1647 return net_run_function(argc
, argv
, func
, net_ads_printer_usage
);
1651 static int net_ads_password(int argc
, const char **argv
)
1654 const char *auth_principal
= opt_user_name
;
1655 const char *auth_password
= opt_password
;
1657 char *new_password
= NULL
;
1662 if (opt_user_name
== NULL
|| opt_password
== NULL
) {
1663 d_fprintf(stderr
, "You must supply an administrator username/password\n");
1668 d_fprintf(stderr
, "ERROR: You must say which username to change password for\n");
1673 if (!strchr_m(user
, '@')) {
1674 asprintf(&c
, "%s@%s", argv
[0], lp_realm());
1678 use_in_memory_ccache();
1679 c
= strchr_m(auth_principal
, '@');
1686 /* use the realm so we can eventually change passwords for users
1687 in realms other than default */
1688 if (!(ads
= ads_init(realm
, opt_workgroup
, opt_host
))) {
1692 /* we don't actually need a full connect, but it's the easy way to
1693 fill in the KDC's addresss */
1696 if (!ads
->config
.realm
) {
1697 d_fprintf(stderr
, "Didn't find the kerberos server!\n");
1702 new_password
= (char *)argv
[1];
1704 asprintf(&prompt
, "Enter new password for %s:", user
);
1705 new_password
= getpass(prompt
);
1709 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
1710 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
1711 if (!ADS_ERR_OK(ret
)) {
1712 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1717 d_printf("Password change for %s completed.\n", user
);
1723 int net_ads_changetrustpw(int argc
, const char **argv
)
1726 char *host_principal
;
1730 if (!secrets_init()) {
1731 DEBUG(1,("Failed to initialise secrets database\n"));
1735 net_use_krb_machine_account();
1737 use_in_memory_ccache();
1739 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
1743 fstrcpy(my_name
, global_myname());
1744 strlower_m(my_name
);
1745 asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
);
1746 d_printf("Changing password for principal: %s\n", host_principal
);
1748 ret
= ads_change_trust_account_password(ads
, host_principal
);
1750 if (!ADS_ERR_OK(ret
)) {
1751 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1753 SAFE_FREE(host_principal
);
1757 d_printf("Password change for principal %s succeeded.\n", host_principal
);
1759 if (lp_use_kerberos_keytab()) {
1760 d_printf("Attempting to update system keytab with new password.\n");
1761 if (ads_keytab_create_default(ads
)) {
1762 d_printf("Failed to update system keytab.\n");
1767 SAFE_FREE(host_principal
);
1773 help for net ads search
1775 static int net_ads_search_usage(int argc
, const char **argv
)
1778 "\nnet ads search <expression> <attributes...>\n"\
1779 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1780 "The expression is a standard LDAP search expression, and the\n"\
1781 "attributes are a list of LDAP fields to show in the results\n\n"\
1782 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1784 net_common_flags_usage(argc
, argv
);
1790 general ADS search function. Useful in diagnosing problems in ADS
1792 static int net_ads_search(int argc
, const char **argv
)
1796 const char *ldap_exp
;
1798 LDAPMessage
*res
= NULL
;
1801 return net_ads_search_usage(argc
, argv
);
1804 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
1811 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
1813 ldap_exp
, attrs
, &res
);
1814 if (!ADS_ERR_OK(rc
)) {
1815 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
1820 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
1822 /* dump the results */
1825 ads_msgfree(ads
, res
);
1833 help for net ads search
1835 static int net_ads_dn_usage(int argc
, const char **argv
)
1838 "\nnet ads dn <dn> <attributes...>\n"\
1839 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1840 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1841 "to show in the results\n\n"\
1842 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1843 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1845 net_common_flags_usage(argc
, argv
);
1851 general ADS search function. Useful in diagnosing problems in ADS
1853 static int net_ads_dn(int argc
, const char **argv
)
1859 LDAPMessage
*res
= NULL
;
1862 return net_ads_dn_usage(argc
, argv
);
1865 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
1872 rc
= ads_do_search_all(ads
, dn
,
1874 "(objectclass=*)", attrs
, &res
);
1875 if (!ADS_ERR_OK(rc
)) {
1876 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
1881 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
1883 /* dump the results */
1886 ads_msgfree(ads
, res
);
1893 help for net ads sid search
1895 static int net_ads_sid_usage(int argc
, const char **argv
)
1898 "\nnet ads sid <sid> <attributes...>\n"\
1899 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1900 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
1901 "to show in the results\n\n"\
1902 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
1904 net_common_flags_usage(argc
, argv
);
1910 general ADS search function. Useful in diagnosing problems in ADS
1912 static int net_ads_sid(int argc
, const char **argv
)
1916 const char *sid_string
;
1918 LDAPMessage
*res
= NULL
;
1922 return net_ads_sid_usage(argc
, argv
);
1925 if (!ADS_ERR_OK(ads_startup(False
, &ads
))) {
1929 sid_string
= argv
[0];
1932 if (!string_to_sid(&sid
, sid_string
)) {
1933 d_fprintf(stderr
, "could not convert sid\n");
1938 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
1939 if (!ADS_ERR_OK(rc
)) {
1940 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
1945 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
1947 /* dump the results */
1950 ads_msgfree(ads
, res
);
1957 static int net_ads_keytab_usage(int argc
, const char **argv
)
1960 "net ads keytab <COMMAND>\n"\
1961 "<COMMAND> can be either:\n"\
1962 " ADD Adds new service principal\n"\
1963 " CREATE Creates a fresh keytab\n"\
1964 " FLUSH Flushes out all keytab entries\n"\
1965 " HELP Prints this help message\n"\
1966 " LIST List the keytab\n"\
1967 "The ADD and LIST command will take arguments, the other commands\n"\
1968 "will not take any arguments. The arguments given to ADD\n"\
1969 "should be a list of principals to add. For example, \n"\
1970 " net ads keytab add srv1 srv2\n"\
1971 "will add principals for the services srv1 and srv2 to the\n"\
1972 "system's keytab.\n"\
1973 "The LIST command takes a keytabname.\n"\
1979 static int net_ads_keytab_flush(int argc
, const char **argv
)
1984 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
1987 ret
= ads_keytab_flush(ads
);
1992 static int net_ads_keytab_add(int argc
, const char **argv
)
1998 d_printf("Processing principals to add...\n");
1999 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
2002 for (i
= 0; i
< argc
; i
++) {
2003 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2009 static int net_ads_keytab_create(int argc
, const char **argv
)
2014 if (!ADS_ERR_OK(ads_startup(True
, &ads
))) {
2017 ret
= ads_keytab_create_default(ads
);
2022 static int net_ads_keytab_list(int argc
, const char **argv
)
2024 const char *keytab
= NULL
;
2030 return ads_keytab_list(keytab
);
2034 int net_ads_keytab(int argc
, const char **argv
)
2036 struct functable func
[] = {
2037 {"ADD", net_ads_keytab_add
},
2038 {"CREATE", net_ads_keytab_create
},
2039 {"FLUSH", net_ads_keytab_flush
},
2040 {"HELP", net_ads_keytab_usage
},
2041 {"LIST", net_ads_keytab_list
},
2045 if (!lp_use_kerberos_keytab()) {
2046 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2047 use keytab functions.\n");
2050 return net_run_function(argc
, argv
, func
, net_ads_keytab_usage
);
2053 static int net_ads_kerberos_usage(int argc
, const char **argv
)
2056 "net ads kerberos <COMMAND>\n"\
2057 "<COMMAND> can be either:\n"\
2058 " RENEW Renew TGT from existing credential cache\n"\
2059 " PAC Dumps the Kerberos PAC\n"\
2060 " KINIT Retrieve Ticket Granting Ticket (TGT)\n"\
2067 static int net_ads_kerberos_renew(int argc
, const char **argv
)
2069 int ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2071 d_printf("failed to renew kerberos ticket: %s\n",
2072 error_message(ret
));
2077 static int net_ads_kerberos_pac(int argc
, const char **argv
)
2079 struct PAC_DATA
*pac
= NULL
;
2080 struct PAC_LOGON_INFO
*info
= NULL
;
2081 TALLOC_CTX
*mem_ctx
= NULL
;
2085 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2090 opt_password
= net_prompt_pass(opt_user_name
);
2092 status
= kerberos_return_pac(mem_ctx
,
2101 2592000, /* one month */
2103 if (!NT_STATUS_IS_OK(status
)) {
2104 d_printf("failed to query kerberos PAC: %s\n",
2109 info
= get_logon_info_from_pac(pac
);
2112 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2113 d_printf("The Pac: %s\n", s
);
2118 TALLOC_FREE(mem_ctx
);
2122 static int net_ads_kerberos_kinit(int argc
, const char **argv
)
2124 TALLOC_CTX
*mem_ctx
= NULL
;
2128 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2133 opt_password
= net_prompt_pass(opt_user_name
);
2135 ret
= kerberos_kinit_password_ext(opt_user_name
,
2143 2592000, /* one month */
2146 d_printf("failed to kinit password: %s\n",
2153 int net_ads_kerberos(int argc
, const char **argv
)
2155 struct functable func
[] = {
2156 {"KINIT", net_ads_kerberos_kinit
},
2157 {"RENEW", net_ads_kerberos_renew
},
2158 {"PAC", net_ads_kerberos_pac
},
2159 {"HELP", net_ads_kerberos_usage
},
2163 return net_run_function(argc
, argv
, func
, net_ads_kerberos_usage
);
2167 int net_ads_help(int argc
, const char **argv
)
2169 struct functable func
[] = {
2170 {"USER", net_ads_user_usage
},
2171 {"GROUP", net_ads_group_usage
},
2172 {"PRINTER", net_ads_printer_usage
},
2173 {"SEARCH", net_ads_search_usage
},
2174 {"INFO", net_ads_info
},
2175 {"JOIN", net_ads_join_usage
},
2176 {"DNS", net_ads_dns_usage
},
2177 {"LEAVE", net_ads_leave
},
2178 {"STATUS", net_ads_status
},
2179 {"PASSWORD", net_ads_password
},
2180 {"CHANGETRUSTPW", net_ads_changetrustpw
},
2184 return net_run_function(argc
, argv
, func
, net_ads_usage
);
2187 int net_ads(int argc
, const char **argv
)
2189 struct functable func
[] = {
2190 {"INFO", net_ads_info
},
2191 {"JOIN", net_ads_join
},
2192 {"TESTJOIN", net_ads_testjoin
},
2193 {"LEAVE", net_ads_leave
},
2194 {"STATUS", net_ads_status
},
2195 {"USER", net_ads_user
},
2196 {"GROUP", net_ads_group
},
2197 {"DNS", net_ads_dns
},
2198 {"PASSWORD", net_ads_password
},
2199 {"CHANGETRUSTPW", net_ads_changetrustpw
},
2200 {"PRINTER", net_ads_printer
},
2201 {"SEARCH", net_ads_search
},
2203 {"SID", net_ads_sid
},
2204 {"WORKGROUP", net_ads_workgroup
},
2205 {"LOOKUP", net_ads_lookup
},
2206 {"KEYTAB", net_ads_keytab
},
2207 {"GPO", net_ads_gpo
},
2208 {"KERBEROS", net_ads_kerberos
},
2209 {"HELP", net_ads_help
},
2213 return net_run_function(argc
, argv
, func
, net_ads_usage
);
2218 static int net_ads_noads(void)
2220 d_fprintf(stderr
, "ADS support not compiled in\n");
2224 int net_ads_keytab(int argc
, const char **argv
)
2226 return net_ads_noads();
2229 int net_ads_kerberos(int argc
, const char **argv
)
2231 return net_ads_noads();
2234 int net_ads_usage(int argc
, const char **argv
)
2236 return net_ads_noads();
2239 int net_ads_help(int argc
, const char **argv
)
2241 return net_ads_noads();
2244 int net_ads_changetrustpw(int argc
, const char **argv
)
2246 return net_ads_noads();
2249 int net_ads_join(int argc
, const char **argv
)
2251 return net_ads_noads();
2254 int net_ads_user(int argc
, const char **argv
)
2256 return net_ads_noads();
2259 int net_ads_group(int argc
, const char **argv
)
2261 return net_ads_noads();
2264 /* this one shouldn't display a message */
2265 int net_ads_check(void)
2270 int net_ads_check_our_domain(void)
2275 int net_ads(int argc
, const char **argv
)
2277 return net_ads_usage(argc
, argv
);
2280 #endif /* WITH_ADS */