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"
25 #include "libsmb/namequery.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "librpc/gen_ndr/ndr_krb5pac.h"
28 #include "../librpc/gen_ndr/ndr_spoolss.h"
29 #include "nsswitch/libwbclient/wbclient.h"
31 #include "libads/cldap.h"
32 #include "../lib/addns/dnsquery.h"
33 #include "../libds/common/flags.h"
34 #include "librpc/gen_ndr/libnet_join.h"
35 #include "libnet/libnet_join.h"
39 #include "../libcli/security/security.h"
40 #include "libsmb/libsmb.h"
41 #include "lib/param/loadparm.h"
42 #include "utils/net_dns.h"
46 /* when we do not have sufficient input parameters to contact a remote domain
47 * we always fall back to our own realm - Guenther*/
49 static const char *assume_own_realm(struct net_context
*c
)
51 if (!c
->opt_host
&& strequal(lp_workgroup(), c
->opt_target_workgroup
)) {
59 do a cldap netlogon query
61 static int net_ads_cldap_netlogon(struct net_context
*c
, ADS_STRUCT
*ads
)
63 char addr
[INET6_ADDRSTRLEN
];
64 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
66 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
68 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads
->ldap
.ss
, ads
->server
.realm
, &reply
) ) {
69 d_fprintf(stderr
, _("CLDAP query failed!\n"));
73 d_printf(_("Information for Domain Controller: %s\n\n"),
76 d_printf(_("Response Type: "));
77 switch (reply
.command
) {
78 case LOGON_SAM_LOGON_USER_UNKNOWN_EX
:
79 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
81 case LOGON_SAM_LOGON_RESPONSE_EX
:
82 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
85 d_printf("0x%x\n", reply
.command
);
89 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply
.domain_uuid
));
93 "\tIs a GC of the forest: %s\n"
94 "\tIs an LDAP server: %s\n"
96 "\tIs running a KDC: %s\n"
97 "\tIs running time services: %s\n"
98 "\tIs the closest DC: %s\n"
100 "\tHas a hardware clock: %s\n"
101 "\tIs a non-domain NC serviced by LDAP server: %s\n"
102 "\tIs NT6 DC that has some secrets: %s\n"
103 "\tIs NT6 DC that has all secrets: %s\n"
104 "\tRuns Active Directory Web Services: %s\n"
105 "\tRuns on Windows 2012 or later: %s\n"),
106 (reply
.server_type
& NBT_SERVER_PDC
) ? _("yes") : _("no"),
107 (reply
.server_type
& NBT_SERVER_GC
) ? _("yes") : _("no"),
108 (reply
.server_type
& NBT_SERVER_LDAP
) ? _("yes") : _("no"),
109 (reply
.server_type
& NBT_SERVER_DS
) ? _("yes") : _("no"),
110 (reply
.server_type
& NBT_SERVER_KDC
) ? _("yes") : _("no"),
111 (reply
.server_type
& NBT_SERVER_TIMESERV
) ? _("yes") : _("no"),
112 (reply
.server_type
& NBT_SERVER_CLOSEST
) ? _("yes") : _("no"),
113 (reply
.server_type
& NBT_SERVER_WRITABLE
) ? _("yes") : _("no"),
114 (reply
.server_type
& NBT_SERVER_GOOD_TIMESERV
) ? _("yes") : _("no"),
115 (reply
.server_type
& NBT_SERVER_NDNC
) ? _("yes") : _("no"),
116 (reply
.server_type
& NBT_SERVER_SELECT_SECRET_DOMAIN_6
) ? _("yes") : _("no"),
117 (reply
.server_type
& NBT_SERVER_FULL_SECRET_DOMAIN_6
) ? _("yes") : _("no"),
118 (reply
.server_type
& NBT_SERVER_ADS_WEB_SERVICE
) ? _("yes") : _("no"),
119 (reply
.server_type
& NBT_SERVER_DS_8
) ? _("yes") : _("no"));
122 printf(_("Forest:\t\t\t%s\n"), reply
.forest
);
123 printf(_("Domain:\t\t\t%s\n"), reply
.dns_domain
);
124 printf(_("Domain Controller:\t%s\n"), reply
.pdc_dns_name
);
126 printf(_("Pre-Win2k Domain:\t%s\n"), reply
.domain_name
);
127 printf(_("Pre-Win2k Hostname:\t%s\n"), reply
.pdc_name
);
129 if (*reply
.user_name
) printf(_("User name:\t%s\n"), reply
.user_name
);
131 printf(_("Server Site Name :\t\t%s\n"), reply
.server_site
);
132 printf(_("Client Site Name :\t\t%s\n"), reply
.client_site
);
134 d_printf(_("NT Version: %d\n"), reply
.nt_version
);
135 d_printf(_("LMNT Token: %.2x\n"), reply
.lmnt_token
);
136 d_printf(_("LM20 Token: %.2x\n"), reply
.lm20_token
);
142 this implements the CLDAP based netlogon lookup requests
143 for finding the domain controller of a ADS domain
145 static int net_ads_lookup(struct net_context
*c
, int argc
, const char **argv
)
150 if (c
->display_usage
) {
155 _("Find the ADS DC using CLDAP lookup.\n"));
159 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
160 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
165 if (!ads
->config
.realm
) {
166 ads
->config
.realm
= discard_const_p(char, c
->opt_target_workgroup
);
167 ads
->ldap
.port
= 389;
170 ret
= net_ads_cldap_netlogon(c
, ads
);
178 #include "audit_logging.h" /* various JSON helpers */
179 #include "auth/common_auth.h"
182 * note: JSON output deliberately bypasses gettext so as to provide the same
183 * output irrespective of the locale.
186 static int net_ads_info_json(ADS_STRUCT
*ads
)
189 char addr
[INET6_ADDRSTRLEN
];
191 struct json_object jsobj
= json_new_object();
192 TALLOC_CTX
*ctx
= NULL
;
195 if (json_is_invalid(&jsobj
)) {
196 d_fprintf(stderr
, _("error setting up JSON value\n"));
201 pass_time
= secrets_fetch_pass_last_set_time(ads
->server
.workgroup
);
203 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
205 ret
= json_add_string (&jsobj
, "LDAP server", addr
);
210 ret
= json_add_string (&jsobj
, "LDAP server name",
211 ads
->config
.ldap_server_name
);
216 ret
= json_add_string (&jsobj
, "Realm", ads
->config
.realm
);
221 ret
= json_add_string (&jsobj
, "Bind Path", ads
->config
.bind_path
);
226 ret
= json_add_int (&jsobj
, "LDAP port", ads
->ldap
.port
);
231 ret
= json_add_int (&jsobj
, "Server time", ads
->config
.current_time
);
236 ret
= json_add_string (&jsobj
, "KDC server", ads
->auth
.kdc_server
);
241 ret
= json_add_int (&jsobj
, "Server time offset",
242 ads
->auth
.time_offset
);
247 ret
= json_add_int (&jsobj
, "Last machine account password change",
253 if (json_is_invalid(&jsobj
)) {
258 ctx
= talloc_new(NULL
);
261 d_fprintf(stderr
, _("Out of memory\n"));
266 json
= json_to_string(ctx
, &jsobj
);
268 d_printf("%s\n", json
);
271 d_fprintf(stderr
, _("error encoding to JSON\n"));
281 #else /* [HAVE_JANSSON] */
283 static int net_ads_info_json(ADS_STRUCT
*)
285 d_fprintf(stderr
, _("JSON support not available\n"));
290 #endif /* [HAVE_JANSSON] */
294 static int net_ads_info(struct net_context
*c
, int argc
, const char **argv
)
297 char addr
[INET6_ADDRSTRLEN
];
300 if (c
->display_usage
) {
305 _("Display information about an Active Directory "
310 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
311 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
315 if (!ads
|| !ads
->config
.realm
) {
316 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
321 /* Try to set the server's current time since we didn't do a full
322 TCP LDAP session initially */
324 if ( !ADS_ERR_OK(ads_current_time( ads
)) ) {
325 d_fprintf( stderr
, _("Failed to get server's current time!\n"));
329 return net_ads_info_json(ads
);
332 pass_time
= secrets_fetch_pass_last_set_time(ads
->server
.workgroup
);
334 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
336 d_printf(_("LDAP server: %s\n"), addr
);
337 d_printf(_("LDAP server name: %s\n"), ads
->config
.ldap_server_name
);
338 d_printf(_("Realm: %s\n"), ads
->config
.realm
);
339 d_printf(_("Bind Path: %s\n"), ads
->config
.bind_path
);
340 d_printf(_("LDAP port: %d\n"), ads
->ldap
.port
);
341 d_printf(_("Server time: %s\n"),
342 http_timestring(talloc_tos(), ads
->config
.current_time
));
344 d_printf(_("KDC server: %s\n"), ads
->auth
.kdc_server
);
345 d_printf(_("Server time offset: %d\n"), ads
->auth
.time_offset
);
347 d_printf(_("Last machine account password change: %s\n"),
348 http_timestring(talloc_tos(), pass_time
));
354 static void use_in_memory_ccache(void) {
355 /* Use in-memory credentials cache so we do not interfere with
356 * existing credentials */
357 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
360 static ADS_STATUS
ads_startup_int(struct net_context
*c
, bool only_own_domain
,
361 uint32_t auth_flags
, ADS_STRUCT
**ads_ret
)
363 ADS_STRUCT
*ads
= NULL
;
365 bool need_password
= false;
366 bool second_time
= false;
368 const char *realm
= NULL
;
369 bool tried_closest_dc
= false;
371 /* lp_realm() should be handled by a command line param,
372 However, the join requires that realm be set in smb.conf
373 and compares our realm with the remote server's so this is
374 ok until someone needs more flexibility */
379 if (only_own_domain
) {
382 realm
= assume_own_realm(c
);
385 ads
= ads_init(realm
, c
->opt_target_workgroup
, c
->opt_host
);
387 if (!c
->opt_user_name
) {
388 c
->opt_user_name
= "administrator";
391 if (c
->opt_user_specified
) {
392 need_password
= true;
396 if (!c
->opt_password
&& need_password
&& !c
->opt_machine_pass
) {
397 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
398 if (!c
->opt_password
) {
400 return ADS_ERROR(LDAP_NO_MEMORY
);
404 if (c
->opt_password
) {
405 use_in_memory_ccache();
406 SAFE_FREE(ads
->auth
.password
);
407 ads
->auth
.password
= smb_xstrdup(c
->opt_password
);
410 ads
->auth
.flags
|= auth_flags
;
411 SAFE_FREE(ads
->auth
.user_name
);
412 ads
->auth
.user_name
= smb_xstrdup(c
->opt_user_name
);
415 * If the username is of the form "name@realm",
416 * extract the realm and convert to upper case.
417 * This is only used to establish the connection.
419 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
421 SAFE_FREE(ads
->auth
.realm
);
422 ads
->auth
.realm
= smb_xstrdup(cp
);
423 if (!strupper_m(ads
->auth
.realm
)) {
425 return ADS_ERROR(LDAP_NO_MEMORY
);
429 status
= ads_connect(ads
);
431 if (!ADS_ERR_OK(status
)) {
433 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
434 NT_STATUS_NO_LOGON_SERVERS
)) {
435 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
440 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
441 need_password
= true;
450 /* when contacting our own domain, make sure we use the closest DC.
451 * This is done by reconnecting to ADS because only the first call to
452 * ads_connect will give us our own sitename */
454 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
456 tried_closest_dc
= true; /* avoid loop */
458 if (!ads_closest_dc(ads
)) {
460 namecache_delete(ads
->server
.realm
, 0x1C);
461 namecache_delete(ads
->server
.workgroup
, 0x1C);
474 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
476 return ads_startup_int(c
, only_own_domain
, 0, ads
);
479 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
481 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
485 Check to see if connection can be made via ads.
486 ads_startup() stores the password in opt_password if it needs to so
487 that rpc or rap can use it without re-prompting.
489 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
494 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
498 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
500 status
= ads_connect(ads
);
501 if ( !ADS_ERR_OK(status
) ) {
509 int net_ads_check_our_domain(struct net_context
*c
)
511 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
514 int net_ads_check(struct net_context
*c
)
516 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
520 determine the netbios workgroup name for a domain
522 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
525 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
527 if (c
->display_usage
) {
529 "net ads workgroup\n"
532 _("Print the workgroup name"));
536 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
537 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
541 if (!ads
->config
.realm
) {
542 ads
->config
.realm
= discard_const_p(char, c
->opt_target_workgroup
);
543 ads
->ldap
.port
= 389;
546 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads
->ldap
.ss
, ads
->server
.realm
, &reply
) ) {
547 d_fprintf(stderr
, _("CLDAP query failed!\n"));
552 d_printf(_("Workgroup: %s\n"), reply
.domain_name
);
561 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
563 char **disp_fields
= (char **) data_area
;
565 if (!field
) { /* must be end of record */
566 if (disp_fields
[0]) {
567 if (!strchr_m(disp_fields
[0], '$')) {
569 d_printf("%-21.21s %s\n",
570 disp_fields
[0], disp_fields
[1]);
572 d_printf("%s\n", disp_fields
[0]);
575 SAFE_FREE(disp_fields
[0]);
576 SAFE_FREE(disp_fields
[1]);
579 if (!values
) /* must be new field, indicate string field */
581 if (strcasecmp_m(field
, "sAMAccountName") == 0) {
582 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
584 if (strcasecmp_m(field
, "description") == 0)
585 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
589 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
591 return net_user_usage(c
, argc
, argv
);
594 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
599 LDAPMessage
*res
=NULL
;
603 if (argc
< 1 || c
->display_usage
)
604 return net_ads_user_usage(c
, argc
, argv
);
606 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
610 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
612 if (!ADS_ERR_OK(status
)) {
613 d_fprintf(stderr
, _("ads_user_add: %s\n"), ads_errstr(status
));
617 if (ads_count_replies(ads
, res
)) {
618 d_fprintf(stderr
, _("ads_user_add: User %s already exists\n"),
623 if (c
->opt_container
) {
624 ou_str
= SMB_STRDUP(c
->opt_container
);
626 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
629 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
631 if (!ADS_ERR_OK(status
)) {
632 d_fprintf(stderr
, _("Could not add user %s: %s\n"), argv
[0],
637 /* if no password is to be set, we're done */
639 d_printf(_("User %s added\n"), argv
[0]);
644 /* try setting the password */
645 if (asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
) == -1) {
648 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
649 ads
->auth
.time_offset
);
651 if (ADS_ERR_OK(status
)) {
652 d_printf(_("User %s added\n"), argv
[0]);
657 /* password didn't set, delete account */
658 d_fprintf(stderr
, _("Could not add user %s. "
659 "Error setting password %s\n"),
660 argv
[0], ads_errstr(status
));
661 ads_msgfree(ads
, res
);
662 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
663 if (ADS_ERR_OK(status
)) {
664 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
665 ads_del_dn(ads
, userdn
);
671 ads_msgfree(ads
, res
);
677 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
679 ADS_STRUCT
*ads
= NULL
;
681 LDAPMessage
*res
= NULL
;
685 const char *attrs
[] = {"memberOf", "primaryGroupID", NULL
};
686 char *searchstring
=NULL
;
690 struct dom_sid primary_group_sid
;
692 enum wbcSidType type
;
694 if (argc
< 1 || c
->display_usage
) {
695 return net_ads_user_usage(c
, argc
, argv
);
698 frame
= talloc_new(talloc_tos());
703 escaped_user
= escape_ldap_string(frame
, argv
[0]);
706 _("ads_user_info: failed to escape user %s\n"),
711 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
716 if (asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
) == -1) {
720 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
721 SAFE_FREE(searchstring
);
723 if (!ADS_ERR_OK(rc
)) {
724 d_fprintf(stderr
, _("ads_search: %s\n"), ads_errstr(rc
));
729 if (!ads_pull_uint32(ads
, res
, "primaryGroupID", &group_rid
)) {
730 d_fprintf(stderr
, _("ads_pull_uint32 failed\n"));
735 rc
= ads_domain_sid(ads
, &primary_group_sid
);
736 if (!ADS_ERR_OK(rc
)) {
737 d_fprintf(stderr
, _("ads_domain_sid: %s\n"), ads_errstr(rc
));
742 sid_append_rid(&primary_group_sid
, group_rid
);
744 wbc_status
= wbcLookupSid((struct wbcDomainSid
*)&primary_group_sid
,
745 NULL
, /* don't look up domain */
748 if (!WBC_ERROR_IS_OK(wbc_status
)) {
749 d_fprintf(stderr
, "wbcLookupSid: %s\n",
750 wbcErrorString(wbc_status
));
755 d_printf("%s\n", primary_group
);
757 wbcFreeMemory(primary_group
);
759 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
760 (LDAPMessage
*)res
, "memberOf");
765 for (i
=0;grouplist
[i
];i
++) {
766 groupname
= ldap_explode_dn(grouplist
[i
], 1);
767 d_printf("%s\n", groupname
[0]);
768 ldap_value_free(groupname
);
770 ldap_value_free(grouplist
);
774 if (res
) ads_msgfree(ads
, res
);
775 if (ads
) ads_destroy(&ads
);
780 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
784 LDAPMessage
*res
= NULL
;
788 return net_ads_user_usage(c
, argc
, argv
);
791 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
795 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
796 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
797 d_printf(_("User %s does not exist.\n"), argv
[0]);
798 ads_msgfree(ads
, res
);
802 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
803 ads_msgfree(ads
, res
);
804 rc
= ads_del_dn(ads
, userdn
);
806 if (ADS_ERR_OK(rc
)) {
807 d_printf(_("User %s deleted\n"), argv
[0]);
811 d_fprintf(stderr
, _("Error deleting user %s: %s\n"), argv
[0],
817 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
819 struct functable func
[] = {
824 N_("Add an AD user"),
825 N_("net ads user add\n"
832 N_("Display information about an AD user"),
833 N_("net ads user info\n"
834 " Display information about an AD user")
840 N_("Delete an AD user"),
841 N_("net ads user delete\n"
842 " Delete an AD user")
844 {NULL
, NULL
, 0, NULL
, NULL
}
848 const char *shortattrs
[] = {"sAMAccountName", NULL
};
849 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
850 char *disp_fields
[2] = {NULL
, NULL
};
853 if (c
->display_usage
) {
859 net_display_usage_from_functable(func
);
863 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
867 if (c
->opt_long_list_entries
)
868 d_printf(_("\nUser name Comment"
869 "\n-----------------------------\n"));
871 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
873 "(objectCategory=user)",
874 c
->opt_long_list_entries
? longattrs
:
875 shortattrs
, usergrp_display
,
878 return ADS_ERR_OK(rc
) ? 0 : -1;
881 return net_run_function(c
, argc
, argv
, "net ads user", func
);
884 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
886 return net_group_usage(c
, argc
, argv
);
889 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
893 LDAPMessage
*res
=NULL
;
897 if (argc
< 1 || c
->display_usage
) {
898 return net_ads_group_usage(c
, argc
, argv
);
901 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
905 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
907 if (!ADS_ERR_OK(status
)) {
908 d_fprintf(stderr
, _("ads_group_add: %s\n"), ads_errstr(status
));
912 if (ads_count_replies(ads
, res
)) {
913 d_fprintf(stderr
, _("ads_group_add: Group %s already exists\n"), argv
[0]);
917 if (c
->opt_container
) {
918 ou_str
= SMB_STRDUP(c
->opt_container
);
920 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
923 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
925 if (ADS_ERR_OK(status
)) {
926 d_printf(_("Group %s added\n"), argv
[0]);
929 d_fprintf(stderr
, _("Could not add group %s: %s\n"), argv
[0],
935 ads_msgfree(ads
, res
);
941 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
945 LDAPMessage
*res
= NULL
;
948 if (argc
< 1 || c
->display_usage
) {
949 return net_ads_group_usage(c
, argc
, argv
);
952 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
956 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
957 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
958 d_printf(_("Group %s does not exist.\n"), argv
[0]);
959 ads_msgfree(ads
, res
);
963 groupdn
= ads_get_dn(ads
, talloc_tos(), res
);
964 ads_msgfree(ads
, res
);
965 rc
= ads_del_dn(ads
, groupdn
);
966 TALLOC_FREE(groupdn
);
967 if (ADS_ERR_OK(rc
)) {
968 d_printf(_("Group %s deleted\n"), argv
[0]);
972 d_fprintf(stderr
, _("Error deleting group %s: %s\n"), argv
[0],
978 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
980 struct functable func
[] = {
985 N_("Add an AD group"),
986 N_("net ads group add\n"
993 N_("Delete an AD group"),
994 N_("net ads group delete\n"
995 " Delete an AD group")
997 {NULL
, NULL
, 0, NULL
, NULL
}
1001 const char *shortattrs
[] = {"sAMAccountName", NULL
};
1002 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
1003 char *disp_fields
[2] = {NULL
, NULL
};
1006 if (c
->display_usage
) {
1011 _("List AD groups"));
1012 net_display_usage_from_functable(func
);
1016 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1020 if (c
->opt_long_list_entries
)
1021 d_printf(_("\nGroup name Comment"
1022 "\n-----------------------------\n"));
1023 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
1025 "(objectCategory=group)",
1026 c
->opt_long_list_entries
? longattrs
:
1027 shortattrs
, usergrp_display
,
1031 return ADS_ERR_OK(rc
) ? 0 : -1;
1033 return net_run_function(c
, argc
, argv
, "net ads group", func
);
1036 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
1042 if (c
->display_usage
) {
1047 _("Display machine account details"));
1051 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1055 rc
= ads_find_machine_acct(ads
, &res
, lp_netbios_name());
1056 if (!ADS_ERR_OK(rc
)) {
1057 d_fprintf(stderr
, _("ads_find_machine_acct: %s\n"), ads_errstr(rc
));
1062 if (ads_count_replies(ads
, res
) == 0) {
1063 d_fprintf(stderr
, _("No machine account for '%s' found\n"), lp_netbios_name());
1073 /*******************************************************************
1074 Leave an AD domain. Windows XP disables the machine account.
1075 We'll try the same. The old code would do an LDAP delete.
1076 That only worked using the machine creds because added the machine
1077 with full control to the computer object's ACL.
1078 *******************************************************************/
1080 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
1083 struct libnet_UnjoinCtx
*r
= NULL
;
1086 if (c
->display_usage
) {
1088 "net ads leave [--keep-account]\n"
1091 _("Leave an AD domain"));
1096 d_fprintf(stderr
, _("No realm set, are we joined ?\n"));
1100 if (!(ctx
= talloc_init("net_ads_leave"))) {
1101 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
1105 if (!c
->opt_kerberos
) {
1106 use_in_memory_ccache();
1110 d_fprintf(stderr
, _("Could not initialise message context. "
1111 "Try running as root\n"));
1115 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
1116 if (!W_ERROR_IS_OK(werr
)) {
1117 d_fprintf(stderr
, _("Could not initialise unjoin context.\n"));
1122 r
->in
.use_kerberos
= c
->opt_kerberos
;
1123 r
->in
.dc_name
= c
->opt_host
;
1124 r
->in
.domain_name
= lp_realm();
1125 r
->in
.admin_account
= c
->opt_user_name
;
1126 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1127 r
->in
.modify_config
= lp_config_backend_is_registry();
1129 /* Try to delete it, but if that fails, disable it. The
1130 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1131 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1132 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
1133 if (c
->opt_keep_account
) {
1134 r
->in
.delete_machine_account
= false;
1136 r
->in
.delete_machine_account
= true;
1139 r
->in
.msg_ctx
= c
->msg_ctx
;
1141 werr
= libnet_Unjoin(ctx
, r
);
1142 if (!W_ERROR_IS_OK(werr
)) {
1143 d_printf(_("Failed to leave domain: %s\n"),
1144 r
->out
.error_string
? r
->out
.error_string
:
1145 get_friendly_werror_msg(werr
));
1149 if (r
->out
.deleted_machine_account
) {
1150 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1151 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1155 /* We couldn't delete it - see if the disable succeeded. */
1156 if (r
->out
.disabled_machine_account
) {
1157 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1158 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1163 /* Based on what we requested, we shouldn't get here, but if
1164 we did, it means the secrets were removed, and therefore
1165 we have left the domain */
1166 d_fprintf(stderr
, _("Machine '%s' Left domain '%s'\n"),
1167 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1173 if (W_ERROR_IS_OK(werr
)) {
1180 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
1182 ADS_STRUCT
*ads
= NULL
;
1185 struct sockaddr_storage dcip
;
1187 if (!secrets_init()) {
1188 DEBUG(1,("Failed to initialise secrets database\n"));
1189 return NT_STATUS_ACCESS_DENIED
;
1192 net_use_krb_machine_account(c
);
1194 get_dc_name(lp_workgroup(), lp_realm(), dc_name
, &dcip
);
1196 status
= ads_startup(c
, true, &ads
);
1197 if (!ADS_ERR_OK(status
)) {
1198 return ads_ntstatus(status
);
1202 return NT_STATUS_OK
;
1206 check that an existing join is OK
1208 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
1211 use_in_memory_ccache();
1213 if (c
->display_usage
) {
1215 "net ads testjoin\n"
1218 _("Test if the existing join is ok"));
1222 /* Display success or failure */
1223 status
= net_ads_join_ok(c
);
1224 if (!NT_STATUS_IS_OK(status
)) {
1225 fprintf(stderr
, _("Join to domain is not valid: %s\n"),
1226 get_friendly_nt_error_msg(status
));
1230 printf(_("Join is OK\n"));
1234 /*******************************************************************
1235 Simple configu checks before beginning the join
1236 ********************************************************************/
1238 static WERROR
check_ads_config( void )
1240 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
1241 d_printf(_("Host is not configured as a member server.\n"));
1242 return WERR_INVALID_DOMAIN_ROLE
;
1245 if (strlen(lp_netbios_name()) > 15) {
1246 d_printf(_("Our netbios name can be at most 15 chars long, "
1247 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1248 (unsigned int)strlen(lp_netbios_name()));
1249 return WERR_INVALID_COMPUTERNAME
;
1252 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1253 d_fprintf(stderr
, _("realm must be set in in %s for ADS "
1254 "join to succeed.\n"), get_dyn_CONFIGFILE());
1255 return WERR_INVALID_PARAMETER
;
1261 /*******************************************************************
1262 Send a DNS update request
1263 *******************************************************************/
1265 #if defined(WITH_DNS_UPDATES)
1266 #include "../lib/addns/dns.h"
1268 static NTSTATUS
net_update_dns_internal(struct net_context
*c
,
1269 TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1270 const char *machine_name
,
1271 const struct sockaddr_storage
*addrs
,
1272 int num_addrs
, bool remove_host
)
1274 struct dns_rr_ns
*nameservers
= NULL
;
1275 int ns_count
= 0, i
;
1276 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1279 const char *dnsdomain
= NULL
;
1280 char *root_domain
= NULL
;
1282 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1283 d_printf(_("No DNS domain configured for %s. "
1284 "Unable to perform DNS Update.\n"), machine_name
);
1285 status
= NT_STATUS_INVALID_PARAMETER
;
1290 status
= ads_dns_lookup_ns(ctx
,
1294 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1295 /* Child domains often do not have NS records. Look
1296 for the NS record for the forest root domain
1297 (rootDomainNamingContext in therootDSE) */
1299 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1300 LDAPMessage
*msg
= NULL
;
1302 ADS_STATUS ads_status
;
1304 if ( !ads
->ldap
.ld
) {
1305 ads_status
= ads_connect( ads
);
1306 if ( !ADS_ERR_OK(ads_status
) ) {
1307 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1312 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1313 "(objectclass=*)", rootname_attrs
, &msg
);
1314 if (!ADS_ERR_OK(ads_status
)) {
1318 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1320 ads_msgfree( ads
, msg
);
1324 root_domain
= ads_build_domain( root_dn
);
1327 ads_msgfree( ads
, msg
);
1329 /* try again for NS servers */
1331 status
= ads_dns_lookup_ns(ctx
,
1336 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1337 DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
1338 "realm\n", ads
->config
.realm
));
1339 if (ns_count
== 0) {
1340 status
= NT_STATUS_UNSUCCESSFUL
;
1345 dnsdomain
= root_domain
;
1349 for (i
=0; i
< ns_count
; i
++) {
1351 uint32_t flags
= DNS_UPDATE_SIGNED
|
1352 DNS_UPDATE_UNSIGNED
|
1353 DNS_UPDATE_UNSIGNED_SUFFICIENT
|
1355 DNS_UPDATE_PROBE_SUFFICIENT
;
1358 flags
&= ~DNS_UPDATE_PROBE_SUFFICIENT
;
1359 flags
&= ~DNS_UPDATE_UNSIGNED_SUFFICIENT
;
1363 * Do not return after PROBE completion if this function
1364 * is called for DNS removal.
1367 flags
&= ~DNS_UPDATE_PROBE_SUFFICIENT
;
1370 status
= NT_STATUS_UNSUCCESSFUL
;
1372 /* Now perform the dns update - we'll try non-secure and if we fail,
1373 we'll follow it up with a secure update */
1375 fstrcpy( dns_server
, nameservers
[i
].hostname
);
1377 dns_err
= DoDNSUpdate(dns_server
,
1384 if (ERR_DNS_IS_OK(dns_err
)) {
1385 status
= NT_STATUS_OK
;
1389 if (ERR_DNS_EQUAL(dns_err
, ERROR_DNS_INVALID_NAME_SERVER
) ||
1390 ERR_DNS_EQUAL(dns_err
, ERROR_DNS_CONNECTION_FAILED
) ||
1391 ERR_DNS_EQUAL(dns_err
, ERROR_DNS_SOCKET_ERROR
)) {
1392 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1393 dns_errstr(dns_err
)));
1397 d_printf(_("DNS Update for %s failed: %s\n"),
1398 machine_name
, dns_errstr(dns_err
));
1399 status
= NT_STATUS_UNSUCCESSFUL
;
1405 SAFE_FREE( root_domain
);
1410 static NTSTATUS
net_update_dns_ext(struct net_context
*c
,
1411 TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
,
1412 const char *hostname
,
1413 struct sockaddr_storage
*iplist
,
1414 int num_addrs
, bool remove_host
)
1416 struct sockaddr_storage
*iplist_alloc
= NULL
;
1417 fstring machine_name
;
1421 fstrcpy(machine_name
, hostname
);
1423 name_to_fqdn( machine_name
, lp_netbios_name() );
1425 if (!strlower_m( machine_name
)) {
1426 return NT_STATUS_INVALID_PARAMETER
;
1430 * If remove_host is true, then remove all IP addresses associated with
1431 * this hostname from the AD server.
1433 if (!remove_host
&& (num_addrs
== 0 || iplist
== NULL
)) {
1435 * Get our ip address
1436 * (not the 127.0.0.x address but a real ip address)
1438 num_addrs
= get_my_ip_address(&iplist_alloc
);
1439 if ( num_addrs
<= 0 ) {
1440 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1441 "non-loopback IP addresses!\n"));
1442 return NT_STATUS_INVALID_PARAMETER
;
1444 iplist
= iplist_alloc
;
1447 status
= net_update_dns_internal(c
, mem_ctx
, ads
, machine_name
,
1448 iplist
, num_addrs
, remove_host
);
1450 SAFE_FREE(iplist_alloc
);
1454 static NTSTATUS
net_update_dns(struct net_context
*c
, TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
, const char *hostname
)
1458 status
= net_update_dns_ext(c
, mem_ctx
, ads
, hostname
, NULL
, 0, false);
1464 /*******************************************************************
1465 ********************************************************************/
1467 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1469 d_printf(_("net ads join [--no-dns-updates] [options]\n"
1470 "Valid options:\n"));
1471 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1472 " The default UPN is in the form host/netbiosname@REALM.\n"));
1473 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1474 " The OU string read from top to bottom without RDNs\n"
1475 " and delimited by a '/'.\n"
1476 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1477 " NB: A backslash '\\' is used as escape at multiple\n"
1478 " levels and may need to be doubled or even\n"
1479 " quadrupled. It is not used as a separator.\n"));
1480 d_printf(_(" machinepass=PASS Set the machine password to a specific value during\n"
1481 " the join. The default password is random.\n"));
1482 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1483 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during join.\n"
1484 " NB: osName and osVer must be specified together for\n"
1485 " either to take effect. The operatingSystemService\n"
1486 " attribute is then also set along with the two\n"
1487 " other attributes.\n"));
1488 d_printf(_(" osServicePack=string Set the operatingSystemServicePack attribute\n"
1489 " during the join.\n"
1490 " NB: If not specified then by default the samba\n"
1491 " version string is used instead.\n"));
1496 static void _net_ads_join_dns_updates(struct net_context
*c
, TALLOC_CTX
*ctx
, struct libnet_JoinCtx
*r
)
1498 #if defined(WITH_DNS_UPDATES)
1499 ADS_STRUCT
*ads_dns
= NULL
;
1504 * In a clustered environment, don't do dynamic dns updates:
1505 * Registering the set of ip addresses that are assigned to
1506 * the interfaces of the node that performs the join does usually
1507 * not have the desired effect, since the local interfaces do not
1508 * carry the complete set of the cluster's public IP addresses.
1509 * And it can also contain internal addresses that should not
1510 * be visible to the outside at all.
1511 * In order to do dns updates in a clustererd setup, use
1512 * net ads dns register.
1514 if (lp_clustering()) {
1515 d_fprintf(stderr
, _("Not doing automatic DNS update in a "
1516 "clustered setup.\n"));
1520 if (!r
->out
.domain_is_ad
) {
1525 * We enter this block with user creds.
1526 * kinit with the machine password to do dns update.
1529 ads_dns
= ads_init(lp_realm(), NULL
, r
->in
.dc_name
);
1531 if (ads_dns
== NULL
) {
1532 d_fprintf(stderr
, _("DNS update failed: out of memory!\n"));
1536 use_in_memory_ccache();
1538 ret
= asprintf(&ads_dns
->auth
.user_name
, "%s$", lp_netbios_name());
1540 d_fprintf(stderr
, _("DNS update failed: out of memory\n"));
1544 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1545 r
->out
.netbios_domain_name
, NULL
, NULL
);
1546 if (ads_dns
->auth
.password
== NULL
) {
1547 d_fprintf(stderr
, _("DNS update failed: out of memory\n"));
1551 ads_dns
->auth
.realm
= SMB_STRDUP(r
->out
.dns_domain_name
);
1552 if (ads_dns
->auth
.realm
== NULL
) {
1553 d_fprintf(stderr
, _("DNS update failed: out of memory\n"));
1557 if (!strupper_m(ads_dns
->auth
.realm
)) {
1558 d_fprintf(stderr
, _("strupper_m %s failed\n"), ads_dns
->auth
.realm
);
1562 ret
= ads_kinit_password(ads_dns
);
1565 _("DNS update failed: kinit failed: %s\n"),
1566 error_message(ret
));
1570 status
= net_update_dns(c
, ctx
, ads_dns
, NULL
);
1571 if (!NT_STATUS_IS_OK(status
)) {
1572 d_fprintf( stderr
, _("DNS update failed: %s\n"),
1577 ads_destroy(&ads_dns
);
1584 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1586 TALLOC_CTX
*ctx
= NULL
;
1587 struct libnet_JoinCtx
*r
= NULL
;
1588 const char *domain
= lp_realm();
1589 WERROR werr
= WERR_NERR_SETUPNOTJOINED
;
1590 bool createupn
= false;
1591 const char *machineupn
= NULL
;
1592 const char *machine_password
= NULL
;
1593 const char *create_in_ou
= NULL
;
1595 const char *os_name
= NULL
;
1596 const char *os_version
= NULL
;
1597 const char *os_servicepack
= NULL
;
1598 bool modify_config
= lp_config_backend_is_registry();
1599 enum libnetjoin_JoinDomNameType domain_name_type
= JoinDomNameTypeDNS
;
1601 if (c
->display_usage
)
1602 return net_ads_join_usage(c
, argc
, argv
);
1604 if (!modify_config
) {
1606 werr
= check_ads_config();
1607 if (!W_ERROR_IS_OK(werr
)) {
1608 d_fprintf(stderr
, _("Invalid configuration. Exiting....\n"));
1613 if (!(ctx
= talloc_init("net_ads_join"))) {
1614 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
1615 werr
= WERR_NOT_ENOUGH_MEMORY
;
1619 if (!c
->opt_kerberos
) {
1620 use_in_memory_ccache();
1623 werr
= libnet_init_JoinCtx(ctx
, &r
);
1624 if (!W_ERROR_IS_OK(werr
)) {
1628 /* process additional command line args */
1630 for ( i
=0; i
<argc
; i
++ ) {
1631 if ( !strncasecmp_m(argv
[i
], "createupn", strlen("createupn")) ) {
1633 machineupn
= get_string_param(argv
[i
]);
1635 else if ( !strncasecmp_m(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1636 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1637 d_fprintf(stderr
, _("Please supply a valid OU path.\n"));
1638 werr
= WERR_INVALID_PARAMETER
;
1642 else if ( !strncasecmp_m(argv
[i
], "osName", strlen("osName")) ) {
1643 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1644 d_fprintf(stderr
, _("Please supply a operating system name.\n"));
1645 werr
= WERR_INVALID_PARAMETER
;
1649 else if ( !strncasecmp_m(argv
[i
], "osVer", strlen("osVer")) ) {
1650 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1651 d_fprintf(stderr
, _("Please supply a valid operating system version.\n"));
1652 werr
= WERR_INVALID_PARAMETER
;
1656 else if ( !strncasecmp_m(argv
[i
], "osServicePack", strlen("osServicePack")) ) {
1657 if ( (os_servicepack
= get_string_param(argv
[i
])) == NULL
) {
1658 d_fprintf(stderr
, _("Please supply a valid servicepack identifier.\n"));
1659 werr
= WERR_INVALID_PARAMETER
;
1663 else if ( !strncasecmp_m(argv
[i
], "machinepass", strlen("machinepass")) ) {
1664 if ( (machine_password
= get_string_param(argv
[i
])) == NULL
) {
1665 d_fprintf(stderr
, _("Please supply a valid password to set as trust account password.\n"));
1666 werr
= WERR_INVALID_PARAMETER
;
1672 if (strchr(domain
, '.') == NULL
) {
1673 domain_name_type
= JoinDomNameTypeUnknown
;
1675 domain_name_type
= JoinDomNameTypeDNS
;
1681 d_fprintf(stderr
, _("Please supply a valid domain name\n"));
1682 werr
= WERR_INVALID_PARAMETER
;
1687 d_fprintf(stderr
, _("Could not initialise message context. "
1688 "Try running as root\n"));
1689 werr
= WERR_ACCESS_DENIED
;
1693 /* Do the domain join here */
1695 r
->in
.domain_name
= domain
;
1696 r
->in
.domain_name_type
= domain_name_type
;
1697 r
->in
.create_upn
= createupn
;
1698 r
->in
.upn
= machineupn
;
1699 r
->in
.account_ou
= create_in_ou
;
1700 r
->in
.os_name
= os_name
;
1701 r
->in
.os_version
= os_version
;
1702 r
->in
.os_servicepack
= os_servicepack
;
1703 r
->in
.dc_name
= c
->opt_host
;
1704 r
->in
.admin_account
= c
->opt_user_name
;
1705 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1706 r
->in
.machine_password
= machine_password
;
1708 r
->in
.use_kerberos
= c
->opt_kerberos
;
1709 r
->in
.modify_config
= modify_config
;
1710 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1711 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1712 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1713 r
->in
.msg_ctx
= c
->msg_ctx
;
1715 werr
= libnet_Join(ctx
, r
);
1716 if (W_ERROR_EQUAL(werr
, WERR_NERR_DCNOTFOUND
) &&
1717 strequal(domain
, lp_realm())) {
1718 r
->in
.domain_name
= lp_workgroup();
1719 r
->in
.domain_name_type
= JoinDomNameTypeNBT
;
1720 werr
= libnet_Join(ctx
, r
);
1722 if (!W_ERROR_IS_OK(werr
)) {
1726 /* Check the short name of the domain */
1728 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1729 d_printf(_("The workgroup in %s does not match the short\n"
1730 "domain name obtained from the server.\n"
1731 "Using the name [%s] from the server.\n"
1732 "You should set \"workgroup = %s\" in %s.\n"),
1733 get_dyn_CONFIGFILE(), r
->out
.netbios_domain_name
,
1734 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1737 d_printf(_("Using short domain name -- %s\n"), r
->out
.netbios_domain_name
);
1739 if (r
->out
.dns_domain_name
) {
1740 d_printf(_("Joined '%s' to dns domain '%s'\n"), r
->in
.machine_name
,
1741 r
->out
.dns_domain_name
);
1743 d_printf(_("Joined '%s' to domain '%s'\n"), r
->in
.machine_name
,
1744 r
->out
.netbios_domain_name
);
1747 /* print out informative error string in case there is one */
1748 if (r
->out
.error_string
!= NULL
) {
1749 d_printf("%s\n", r
->out
.error_string
);
1753 * We try doing the dns update (if it was compiled in
1754 * and if it was not disabled on the command line).
1755 * If the dns update fails, we still consider the join
1756 * operation as succeeded if we came this far.
1758 if (!c
->opt_no_dns_updates
) {
1759 _net_ads_join_dns_updates(c
, ctx
, r
);
1768 /* issue an overall failure message at the end. */
1769 d_printf(_("Failed to join domain: %s\n"),
1770 r
&& r
->out
.error_string
? r
->out
.error_string
:
1771 get_friendly_werror_msg(werr
));
1777 /*******************************************************************
1778 ********************************************************************/
1780 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1782 #if defined(WITH_DNS_UPDATES)
1787 const char *hostname
= NULL
;
1788 const char **addrs_list
= NULL
;
1789 struct sockaddr_storage
*addrs
= NULL
;
1794 talloc_enable_leak_report();
1797 if (argc
<= 1 && lp_clustering() && lp_cluster_addresses() == NULL
) {
1798 d_fprintf(stderr
, _("Refusing DNS updates with automatic "
1799 "detection of addresses in a clustered "
1801 c
->display_usage
= true;
1804 if (c
->display_usage
) {
1806 "net ads dns register [hostname [IP [IP...]]]\n"
1809 _("Register hostname with DNS\n"));
1813 if (!(ctx
= talloc_init("net_ads_dns"))) {
1814 d_fprintf(stderr
, _("Could not initialise talloc context\n"));
1823 num_addrs
= argc
- 1;
1824 addrs_list
= &argv
[1];
1825 } else if (lp_clustering()) {
1826 addrs_list
= lp_cluster_addresses();
1827 num_addrs
= str_list_length(addrs_list
);
1830 if (num_addrs
> 0) {
1831 addrs
= talloc_zero_array(ctx
, struct sockaddr_storage
, num_addrs
);
1832 if (addrs
== NULL
) {
1833 d_fprintf(stderr
, _("Error allocating memory!\n"));
1839 for (count
= 0; count
< num_addrs
; count
++) {
1840 if (!interpret_string_addr(&addrs
[count
], addrs_list
[count
], 0)) {
1841 d_fprintf(stderr
, "%s '%s'.\n",
1842 _("Cannot interpret address"),
1849 status
= ads_startup(c
, true, &ads
);
1850 if ( !ADS_ERR_OK(status
) ) {
1851 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1856 ntstatus
= net_update_dns_ext(c
, ctx
, ads
, hostname
, addrs
, num_addrs
, false);
1857 if (!NT_STATUS_IS_OK(ntstatus
)) {
1858 d_fprintf( stderr
, _("DNS update failed!\n") );
1859 ads_destroy( &ads
);
1864 d_fprintf( stderr
, _("Successfully registered hostname with DNS\n") );
1872 _("DNS update support not enabled at compile time!\n"));
1877 static int net_ads_dns_unregister(struct net_context
*c
,
1881 #if defined(WITH_DNS_UPDATES)
1886 const char *hostname
= NULL
;
1889 talloc_enable_leak_report();
1893 c
->display_usage
= true;
1896 if (c
->display_usage
) {
1898 "net ads dns unregister [hostname]\n"
1901 _("Register hostname with DNS\n"));
1905 if (!(ctx
= talloc_init("net_ads_dns"))) {
1906 d_fprintf(stderr
, _("Could not initialise talloc context\n"));
1910 /* Get the hostname for un-registering */
1913 status
= ads_startup(c
, true, &ads
);
1914 if ( !ADS_ERR_OK(status
) ) {
1915 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1920 ntstatus
= net_update_dns_ext(c
, ctx
, ads
, hostname
, NULL
, 0, true);
1921 if (!NT_STATUS_IS_OK(ntstatus
)) {
1922 d_fprintf( stderr
, _("DNS update failed!\n") );
1923 ads_destroy( &ads
);
1928 d_fprintf( stderr
, _("Successfully un-registered hostname from DNS\n"));
1936 _("DNS update support not enabled at compile time!\n"));
1941 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1943 #if defined(WITH_DNS_UPDATES)
1947 talloc_enable_leak_report();
1950 if (argc
!= 2 || c
->display_usage
) {
1955 _("net ads dns gethostbyname <server> <name>\n"),
1956 _(" Look up hostname from the AD\n"
1957 " server\tName server to use\n"
1958 " name\tName to look up\n"));
1962 err
= do_gethostbyname(argv
[0], argv
[1]);
1963 if (!ERR_DNS_IS_OK(err
)) {
1964 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1965 dns_errstr(err
), ERROR_DNS_V(err
));
1971 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1973 struct functable func
[] = {
1976 net_ads_dns_register
,
1978 N_("Add host dns entry to AD"),
1979 N_("net ads dns register\n"
1980 " Add host dns entry to AD")
1984 net_ads_dns_unregister
,
1986 N_("Remove host dns entry from AD"),
1987 N_("net ads dns unregister\n"
1988 " Remove host dns entry from AD")
1992 net_ads_dns_gethostbyname
,
1995 N_("net ads dns gethostbyname\n"
1998 {NULL
, NULL
, 0, NULL
, NULL
}
2001 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
2004 /*******************************************************************
2005 ********************************************************************/
2007 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
2010 "\nnet ads printer search <printer>"
2011 "\n\tsearch for a printer in the directory\n"
2012 "\nnet ads printer info <printer> <server>"
2013 "\n\tlookup info in directory for printer on server"
2014 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2015 "\nnet ads printer publish <printername>"
2016 "\n\tpublish printer in directory"
2017 "\n\t(note: printer name is required)\n"
2018 "\nnet ads printer remove <printername>"
2019 "\n\tremove printer from directory"
2020 "\n\t(note: printer name is required)\n"));
2024 /*******************************************************************
2025 ********************************************************************/
2027 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
2031 LDAPMessage
*res
= NULL
;
2033 if (c
->display_usage
) {
2035 "net ads printer search\n"
2038 _("List printers in the AD"));
2042 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2046 rc
= ads_find_printers(ads
, &res
);
2048 if (!ADS_ERR_OK(rc
)) {
2049 d_fprintf(stderr
, _("ads_find_printer: %s\n"), ads_errstr(rc
));
2050 ads_msgfree(ads
, res
);
2055 if (ads_count_replies(ads
, res
) == 0) {
2056 d_fprintf(stderr
, _("No results found\n"));
2057 ads_msgfree(ads
, res
);
2063 ads_msgfree(ads
, res
);
2068 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
2072 const char *servername
, *printername
;
2073 LDAPMessage
*res
= NULL
;
2075 if (c
->display_usage
) {
2078 _("net ads printer info [printername [servername]]\n"
2079 " Display printer info from AD\n"
2080 " printername\tPrinter name or wildcard\n"
2081 " servername\tName of the print server\n"));
2085 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2090 printername
= argv
[0];
2096 servername
= argv
[1];
2098 servername
= lp_netbios_name();
2101 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
2103 if (!ADS_ERR_OK(rc
)) {
2104 d_fprintf(stderr
, _("Server '%s' not found: %s\n"),
2105 servername
, ads_errstr(rc
));
2106 ads_msgfree(ads
, res
);
2111 if (ads_count_replies(ads
, res
) == 0) {
2112 d_fprintf(stderr
, _("Printer '%s' not found\n"), printername
);
2113 ads_msgfree(ads
, res
);
2119 ads_msgfree(ads
, res
);
2125 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
2129 const char *servername
, *printername
;
2130 struct cli_state
*cli
= NULL
;
2131 struct rpc_pipe_client
*pipe_hnd
= NULL
;
2132 struct sockaddr_storage server_ss
;
2134 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
2135 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
2136 char *prt_dn
, *srv_dn
, **srv_cn
;
2137 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
2138 LDAPMessage
*res
= NULL
;
2141 if (argc
< 1 || c
->display_usage
) {
2144 _("net ads printer publish <printername> [servername]\n"
2145 " Publish printer in AD\n"
2146 " printername\tName of the printer\n"
2147 " servername\tName of the print server\n"));
2148 talloc_destroy(mem_ctx
);
2152 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2153 talloc_destroy(mem_ctx
);
2157 printername
= argv
[0];
2160 servername
= argv
[1];
2162 servername
= lp_netbios_name();
2165 /* Get printer data from SPOOLSS */
2167 ok
= resolve_name(servername
, &server_ss
, 0x20, false);
2169 d_fprintf(stderr
, _("Could not find server %s\n"),
2172 talloc_destroy(mem_ctx
);
2176 nt_status
= cli_full_connection(&cli
, lp_netbios_name(), servername
,
2179 c
->opt_user_name
, c
->opt_workgroup
,
2180 c
->opt_password
? c
->opt_password
: "",
2181 CLI_FULL_CONNECTION_USE_KERBEROS
,
2182 SMB_SIGNING_IPC_DEFAULT
);
2184 if (NT_STATUS_IS_ERR(nt_status
)) {
2185 d_fprintf(stderr
, _("Unable to open a connection to %s to "
2186 "obtain data for %s\n"),
2187 servername
, printername
);
2189 talloc_destroy(mem_ctx
);
2193 /* Publish on AD server */
2195 ads_find_machine_acct(ads
, &res
, servername
);
2197 if (ads_count_replies(ads
, res
) == 0) {
2198 d_fprintf(stderr
, _("Could not find machine account for server "
2202 talloc_destroy(mem_ctx
);
2206 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
2207 srv_cn
= ldap_explode_dn(srv_dn
, 1);
2209 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
2210 printername_escaped
= escape_rdn_val_string_alloc(printername
);
2211 if (!srv_cn_escaped
|| !printername_escaped
) {
2212 SAFE_FREE(srv_cn_escaped
);
2213 SAFE_FREE(printername_escaped
);
2214 d_fprintf(stderr
, _("Internal error, out of memory!"));
2216 talloc_destroy(mem_ctx
);
2220 if (asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
) == -1) {
2221 SAFE_FREE(srv_cn_escaped
);
2222 SAFE_FREE(printername_escaped
);
2223 d_fprintf(stderr
, _("Internal error, out of memory!"));
2225 talloc_destroy(mem_ctx
);
2229 SAFE_FREE(srv_cn_escaped
);
2230 SAFE_FREE(printername_escaped
);
2232 nt_status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_spoolss
, &pipe_hnd
);
2233 if (!NT_STATUS_IS_OK(nt_status
)) {
2234 d_fprintf(stderr
, _("Unable to open a connection to the spoolss pipe on %s\n"),
2238 talloc_destroy(mem_ctx
);
2242 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
2246 talloc_destroy(mem_ctx
);
2250 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
2251 if (!ADS_ERR_OK(rc
)) {
2252 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
2255 talloc_destroy(mem_ctx
);
2259 d_printf("published printer\n");
2262 talloc_destroy(mem_ctx
);
2267 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
2271 const char *servername
;
2273 LDAPMessage
*res
= NULL
;
2275 if (argc
< 1 || c
->display_usage
) {
2278 _("net ads printer remove <printername> [servername]\n"
2279 " Remove a printer from the AD\n"
2280 " printername\tName of the printer\n"
2281 " servername\tName of the print server\n"));
2285 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2290 servername
= argv
[1];
2292 servername
= lp_netbios_name();
2295 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
2297 if (!ADS_ERR_OK(rc
)) {
2298 d_fprintf(stderr
, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc
));
2299 ads_msgfree(ads
, res
);
2304 if (ads_count_replies(ads
, res
) == 0) {
2305 d_fprintf(stderr
, _("Printer '%s' not found\n"), argv
[1]);
2306 ads_msgfree(ads
, res
);
2311 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
2312 ads_msgfree(ads
, res
);
2313 rc
= ads_del_dn(ads
, prt_dn
);
2314 TALLOC_FREE(prt_dn
);
2316 if (!ADS_ERR_OK(rc
)) {
2317 d_fprintf(stderr
, _("ads_del_dn: %s\n"), ads_errstr(rc
));
2326 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
2328 struct functable func
[] = {
2331 net_ads_printer_search
,
2333 N_("Search for a printer"),
2334 N_("net ads printer search\n"
2335 " Search for a printer")
2339 net_ads_printer_info
,
2341 N_("Display printer information"),
2342 N_("net ads printer info\n"
2343 " Display printer information")
2347 net_ads_printer_publish
,
2349 N_("Publish a printer"),
2350 N_("net ads printer publish\n"
2351 " Publish a printer")
2355 net_ads_printer_remove
,
2357 N_("Delete a printer"),
2358 N_("net ads printer remove\n"
2359 " Delete a printer")
2361 {NULL
, NULL
, 0, NULL
, NULL
}
2364 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
2368 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
2371 const char *auth_principal
= c
->opt_user_name
;
2372 const char *auth_password
= c
->opt_password
;
2373 const char *realm
= NULL
;
2374 const char *new_password
= NULL
;
2377 char pwd
[256] = {0};
2380 if (c
->display_usage
) {
2383 _("net ads password <username>\n"
2384 " Change password for user\n"
2385 " username\tName of user to change password for\n"));
2389 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
2390 d_fprintf(stderr
, _("You must supply an administrator "
2391 "username/password\n"));
2396 d_fprintf(stderr
, _("ERROR: You must say which username to "
2397 "change password for\n"));
2402 if (!strchr_m(user
, '@')) {
2403 if (asprintf(&chr
, "%s@%s", argv
[0], lp_realm()) == -1) {
2409 use_in_memory_ccache();
2410 chr
= strchr_m(auth_principal
, '@');
2417 /* use the realm so we can eventually change passwords for users
2418 in realms other than default */
2419 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
2423 /* we don't actually need a full connect, but it's the easy way to
2424 fill in the KDC's addresss */
2427 if (!ads
->config
.realm
) {
2428 d_fprintf(stderr
, _("Didn't find the kerberos server!\n"));
2434 new_password
= (const char *)argv
[1];
2438 if (asprintf(&prompt
, _("Enter new password for %s:"), user
) == -1) {
2441 rc
= samba_getpass(prompt
, pwd
, sizeof(pwd
), false, true);
2449 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
2450 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
2451 memset(pwd
, '\0', sizeof(pwd
));
2452 if (!ADS_ERR_OK(ret
)) {
2453 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2458 d_printf(_("Password change for %s completed.\n"), user
);
2464 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2467 char *host_principal
;
2471 if (c
->display_usage
) {
2473 "net ads changetrustpw\n"
2476 _("Change the machine account's trust password"));
2480 if (!secrets_init()) {
2481 DEBUG(1,("Failed to initialise secrets database\n"));
2485 net_use_krb_machine_account(c
);
2487 use_in_memory_ccache();
2489 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2493 fstrcpy(my_name
, lp_netbios_name());
2494 if (!strlower_m(my_name
)) {
2499 if (asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
) == -1) {
2503 d_printf(_("Changing password for principal: %s\n"), host_principal
);
2505 ret
= ads_change_trust_account_password(ads
, host_principal
);
2507 if (!ADS_ERR_OK(ret
)) {
2508 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2510 SAFE_FREE(host_principal
);
2514 d_printf(_("Password change for principal %s succeeded.\n"), host_principal
);
2516 if (USE_SYSTEM_KEYTAB
) {
2517 d_printf(_("Attempting to update system keytab with new password.\n"));
2518 if (ads_keytab_create_default(ads
)) {
2519 d_printf(_("Failed to update system keytab.\n"));
2524 SAFE_FREE(host_principal
);
2530 help for net ads search
2532 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
2535 "\nnet ads search <expression> <attributes...>\n"
2536 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2537 "The expression is a standard LDAP search expression, and the\n"
2538 "attributes are a list of LDAP fields to show in the results.\n\n"
2539 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2541 net_common_flags_usage(c
, argc
, argv
);
2547 general ADS search function. Useful in diagnosing problems in ADS
2549 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
2553 const char *ldap_exp
;
2555 LDAPMessage
*res
= NULL
;
2557 if (argc
< 1 || c
->display_usage
) {
2558 return net_ads_search_usage(c
, argc
, argv
);
2561 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2568 rc
= ads_do_search_retry(ads
, ads
->config
.bind_path
,
2570 ldap_exp
, attrs
, &res
);
2571 if (!ADS_ERR_OK(rc
)) {
2572 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2577 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2579 /* dump the results */
2582 ads_msgfree(ads
, res
);
2590 help for net ads search
2592 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
2595 "\nnet ads dn <dn> <attributes...>\n"
2596 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2597 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2598 "to show in the results\n\n"
2599 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2600 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2602 net_common_flags_usage(c
, argc
, argv
);
2608 general ADS search function. Useful in diagnosing problems in ADS
2610 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
2616 LDAPMessage
*res
= NULL
;
2618 if (argc
< 1 || c
->display_usage
) {
2619 return net_ads_dn_usage(c
, argc
, argv
);
2622 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2629 rc
= ads_do_search_all(ads
, dn
,
2631 "(objectclass=*)", attrs
, &res
);
2632 if (!ADS_ERR_OK(rc
)) {
2633 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2638 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2640 /* dump the results */
2643 ads_msgfree(ads
, res
);
2650 help for net ads sid search
2652 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2655 "\nnet ads sid <sid> <attributes...>\n"
2656 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2657 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2658 "to show in the results\n\n"
2659 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2661 net_common_flags_usage(c
, argc
, argv
);
2667 general ADS search function. Useful in diagnosing problems in ADS
2669 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2673 const char *sid_string
;
2675 LDAPMessage
*res
= NULL
;
2678 if (argc
< 1 || c
->display_usage
) {
2679 return net_ads_sid_usage(c
, argc
, argv
);
2682 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2686 sid_string
= argv
[0];
2689 if (!string_to_sid(&sid
, sid_string
)) {
2690 d_fprintf(stderr
, _("could not convert sid\n"));
2695 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2696 if (!ADS_ERR_OK(rc
)) {
2697 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2702 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2704 /* dump the results */
2707 ads_msgfree(ads
, res
);
2713 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2718 if (c
->display_usage
) {
2720 "net ads keytab flush\n"
2723 _("Delete the whole keytab"));
2727 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2730 ret
= ads_keytab_flush(ads
);
2735 static int net_ads_keytab_add(struct net_context
*c
,
2744 if (c
->display_usage
) {
2747 _("net ads keytab add <principal> [principal ...]\n"
2748 " Add principals to local keytab\n"
2749 " principal\tKerberos principal to add to "
2754 d_printf(_("Processing principals to add...\n"));
2755 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2758 for (i
= 0; i
< argc
; i
++) {
2759 ret
|= ads_keytab_add_entry(ads
, argv
[i
], update_ads
);
2765 static int net_ads_keytab_add_default(struct net_context
*c
,
2769 return net_ads_keytab_add(c
, argc
, argv
, false);
2772 static int net_ads_keytab_add_update_ads(struct net_context
*c
,
2776 return net_ads_keytab_add(c
, argc
, argv
, true);
2779 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2784 if (c
->display_usage
) {
2786 "net ads keytab create\n"
2789 _("Create new default keytab"));
2793 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2796 ret
= ads_keytab_create_default(ads
);
2801 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2803 const char *keytab
= NULL
;
2805 if (c
->display_usage
) {
2808 _("net ads keytab list [keytab]\n"
2809 " List a local keytab\n"
2810 " keytab\tKeytab to list\n"));
2818 return ads_keytab_list(keytab
);
2822 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2824 struct functable func
[] = {
2827 net_ads_keytab_add_default
,
2829 N_("Add a service principal"),
2830 N_("net ads keytab add\n"
2831 " Add a service principal, updates keytab file only.")
2835 net_ads_keytab_add_update_ads
,
2837 N_("Add a service principal"),
2838 N_("net ads keytab add_update_ads\n"
2839 " Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
2843 net_ads_keytab_create
,
2845 N_("Create a fresh keytab"),
2846 N_("net ads keytab create\n"
2847 " Create a fresh keytab or update exising one.")
2851 net_ads_keytab_flush
,
2853 N_("Remove all keytab entries"),
2854 N_("net ads keytab flush\n"
2855 " Remove all keytab entries")
2859 net_ads_keytab_list
,
2861 N_("List a keytab"),
2862 N_("net ads keytab list\n"
2865 {NULL
, NULL
, 0, NULL
, NULL
}
2868 if (!USE_KERBEROS_KEYTAB
) {
2869 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2870 "keytab method to use keytab functions.\n"));
2873 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2876 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2880 if (c
->display_usage
) {
2882 "net ads kerberos renew\n"
2885 _("Renew TGT from existing credential cache"));
2889 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2891 d_printf(_("failed to renew kerberos ticket: %s\n"),
2892 error_message(ret
));
2897 static int net_ads_kerberos_pac_common(struct net_context
*c
, int argc
, const char **argv
,
2898 struct PAC_DATA_CTR
**pac_data_ctr
)
2902 const char *impersonate_princ_s
= NULL
;
2903 const char *local_service
= NULL
;
2906 for (i
=0; i
<argc
; i
++) {
2907 if (strnequal(argv
[i
], "impersonate", strlen("impersonate"))) {
2908 impersonate_princ_s
= get_string_param(argv
[i
]);
2909 if (impersonate_princ_s
== NULL
) {
2913 if (strnequal(argv
[i
], "local_service", strlen("local_service"))) {
2914 local_service
= get_string_param(argv
[i
]);
2915 if (local_service
== NULL
) {
2921 if (local_service
== NULL
) {
2922 local_service
= talloc_asprintf(c
, "%s$@%s",
2923 lp_netbios_name(), lp_realm());
2924 if (local_service
== NULL
) {
2929 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2931 status
= kerberos_return_pac(c
,
2940 2592000, /* one month */
2941 impersonate_princ_s
,
2944 if (!NT_STATUS_IS_OK(status
)) {
2945 d_printf(_("failed to query kerberos PAC: %s\n"),
2955 static int net_ads_kerberos_pac_dump(struct net_context
*c
, int argc
, const char **argv
)
2957 struct PAC_DATA_CTR
*pac_data_ctr
= NULL
;
2960 enum PAC_TYPE type
= 0;
2962 if (c
->display_usage
) {
2964 "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
2967 _("Dump the Kerberos PAC"));
2971 for (i
=0; i
<argc
; i
++) {
2972 if (strnequal(argv
[i
], "pac_buffer_type", strlen("pac_buffer_type"))) {
2973 type
= get_int_param(argv
[i
]);
2977 ret
= net_ads_kerberos_pac_common(c
, argc
, argv
, &pac_data_ctr
);
2986 s
= NDR_PRINT_STRUCT_STRING(c
, PAC_DATA
,
2987 pac_data_ctr
->pac_data
);
2989 d_printf(_("The Pac: %s\n"), s
);
2996 for (i
=0; i
< pac_data_ctr
->pac_data
->num_buffers
; i
++) {
3000 if (pac_data_ctr
->pac_data
->buffers
[i
].type
!= type
) {
3004 s
= NDR_PRINT_UNION_STRING(c
, PAC_INFO
, type
,
3005 pac_data_ctr
->pac_data
->buffers
[i
].info
);
3007 d_printf(_("The Pac: %s\n"), s
);
3016 static int net_ads_kerberos_pac_save(struct net_context
*c
, int argc
, const char **argv
)
3018 struct PAC_DATA_CTR
*pac_data_ctr
= NULL
;
3019 char *filename
= NULL
;
3023 if (c
->display_usage
) {
3025 "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3028 _("Save the Kerberos PAC"));
3032 for (i
=0; i
<argc
; i
++) {
3033 if (strnequal(argv
[i
], "filename", strlen("filename"))) {
3034 filename
= get_string_param(argv
[i
]);
3035 if (filename
== NULL
) {
3041 ret
= net_ads_kerberos_pac_common(c
, argc
, argv
, &pac_data_ctr
);
3046 if (filename
== NULL
) {
3047 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3051 /* save the raw format */
3052 if (!file_save(filename
, pac_data_ctr
->pac_blob
.data
, pac_data_ctr
->pac_blob
.length
)) {
3053 d_printf(_("failed to save PAC in %s\n"), filename
);
3060 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
3062 struct functable func
[] = {
3065 net_ads_kerberos_pac_dump
,
3067 N_("Dump Kerberos PAC"),
3068 N_("net ads kerberos pac dump\n"
3069 " Dump a Kerberos PAC to stdout")
3073 net_ads_kerberos_pac_save
,
3075 N_("Save Kerberos PAC"),
3076 N_("net ads kerberos pac save\n"
3077 " Save a Kerberos PAC in a file")
3080 {NULL
, NULL
, 0, NULL
, NULL
}
3083 return net_run_function(c
, argc
, argv
, "net ads kerberos pac", func
);
3086 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
3088 TALLOC_CTX
*mem_ctx
= NULL
;
3092 if (c
->display_usage
) {
3094 "net ads kerberos kinit\n"
3097 _("Get Ticket Granting Ticket (TGT) for the user"));
3101 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
3106 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
3108 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
3116 2592000, /* one month */
3119 d_printf(_("failed to kinit password: %s\n"),
3126 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
3128 struct functable func
[] = {
3131 net_ads_kerberos_kinit
,
3133 N_("Retrieve Ticket Granting Ticket (TGT)"),
3134 N_("net ads kerberos kinit\n"
3135 " Receive Ticket Granting Ticket (TGT)")
3139 net_ads_kerberos_renew
,
3141 N_("Renew Ticket Granting Ticket from credential cache"),
3142 N_("net ads kerberos renew\n"
3143 " Renew Ticket Granting Ticket (TGT) from "
3148 net_ads_kerberos_pac
,
3150 N_("Dump Kerberos PAC"),
3151 N_("net ads kerberos pac\n"
3152 " Dump Kerberos PAC")
3154 {NULL
, NULL
, 0, NULL
, NULL
}
3157 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
3160 static int net_ads_setspn_list(struct net_context
*c
, int argc
, const char **argv
)
3164 ADS_STRUCT
*ads
= NULL
;
3165 if (c
->display_usage
) {
3168 _("net ads setspn list <machinename>\n"));
3172 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
3177 ok
= ads_setspn_list(ads
, argv
[0]);
3179 ok
= ads_setspn_list(ads
, lp_netbios_name());
3191 static int net_ads_setspn_add(struct net_context
*c
, int argc
, const char **argv
)
3195 ADS_STRUCT
*ads
= NULL
;
3196 if (c
->display_usage
|| argc
< 1) {
3199 _("net ads setspn add <machinename> SPN\n"));
3203 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
3208 ok
= ads_setspn_add(ads
, argv
[0], argv
[1]);
3210 ok
= ads_setspn_add(ads
, lp_netbios_name(), argv
[0]);
3222 static int net_ads_setspn_delete(struct net_context
*c
, int argc
, const char **argv
)
3226 ADS_STRUCT
*ads
= NULL
;
3227 if (c
->display_usage
|| argc
< 1) {
3230 _("net ads setspn delete <machinename> SPN\n"));
3234 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
3239 ok
= ads_setspn_delete(ads
, argv
[0], argv
[1]);
3241 ok
= ads_setspn_delete(ads
, lp_netbios_name(), argv
[0]);
3253 int net_ads_setspn(struct net_context
*c
, int argc
, const char **argv
)
3255 struct functable func
[] = {
3258 net_ads_setspn_list
,
3260 N_("List Service Principal Names (SPN)"),
3261 N_("net ads setspn list machine\n"
3262 " List Service Principal Names (SPN)")
3268 N_("Add Service Principal Names (SPN)"),
3269 N_("net ads setspn add machine spn\n"
3270 " Add Service Principal Names (SPN)")
3274 net_ads_setspn_delete
,
3276 N_("Delete Service Principal Names (SPN)"),
3277 N_("net ads setspn delete machine spn\n"
3278 " Delete Service Principal Names (SPN)")
3280 {NULL
, NULL
, 0, NULL
, NULL
}
3283 return net_run_function(c
, argc
, argv
, "net ads setspn", func
);
3286 static int net_ads_enctype_lookup_account(struct net_context
*c
,
3288 const char *account
,
3290 const char **enctype_str
)
3293 const char *attrs
[] = {
3294 "msDS-SupportedEncryptionTypes",
3301 filter
= talloc_asprintf(c
, "(&(objectclass=user)(sAMAccountName=%s))",
3303 if (filter
== NULL
) {
3307 status
= ads_search(ads
, res
, filter
, attrs
);
3308 if (!ADS_ERR_OK(status
)) {
3309 d_printf(_("no account found with filter: %s\n"), filter
);
3313 count
= ads_count_replies(ads
, *res
);
3318 d_printf(_("no account found with filter: %s\n"), filter
);
3321 d_printf(_("multiple accounts found with filter: %s\n"), filter
);
3326 *enctype_str
= ads_pull_string(ads
, c
, *res
,
3327 "msDS-SupportedEncryptionTypes");
3328 if (*enctype_str
== NULL
) {
3329 d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3339 static void net_ads_enctype_dump_enctypes(const char *username
,
3340 const char *enctype_str
)
3342 int enctypes
= atoi(enctype_str
);
3344 d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3345 username
, enctypes
, enctypes
);
3347 printf("[%s] 0x%08x DES-CBC-CRC\n",
3348 enctypes
& ENC_CRC32
? "X" : " ",
3350 printf("[%s] 0x%08x DES-CBC-MD5\n",
3351 enctypes
& ENC_RSA_MD5
? "X" : " ",
3353 printf("[%s] 0x%08x RC4-HMAC\n",
3354 enctypes
& ENC_RC4_HMAC_MD5
? "X" : " ",
3356 printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3357 enctypes
& ENC_HMAC_SHA1_96_AES128
? "X" : " ",
3358 ENC_HMAC_SHA1_96_AES128
);
3359 printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3360 enctypes
& ENC_HMAC_SHA1_96_AES256
? "X" : " ",
3361 ENC_HMAC_SHA1_96_AES256
);
3364 static int net_ads_enctypes_list(struct net_context
*c
, int argc
, const char **argv
)
3368 ADS_STRUCT
*ads
= NULL
;
3369 LDAPMessage
*res
= NULL
;
3370 const char *str
= NULL
;
3372 if (c
->display_usage
|| (argc
< 1)) {
3374 "net ads enctypes list\n"
3377 _("List supported enctypes"));
3381 status
= ads_startup(c
, false, &ads
);
3382 if (!ADS_ERR_OK(status
)) {
3383 printf("startup failed\n");
3387 ret
= net_ads_enctype_lookup_account(c
, ads
, argv
[0], &res
, &str
);
3392 net_ads_enctype_dump_enctypes(argv
[0], str
);
3396 ads_msgfree(ads
, res
);
3402 static int net_ads_enctypes_set(struct net_context
*c
, int argc
, const char **argv
)
3407 LDAPMessage
*res
= NULL
;
3408 const char *etype_list_str
;
3411 uint32_t etype_list
;
3414 if (c
->display_usage
|| argc
< 1) {
3416 "net ads enctypes set <sAMAccountName> [enctypes]\n"
3419 _("Set supported enctypes"));
3423 status
= ads_startup(c
, false, &ads
);
3424 if (!ADS_ERR_OK(status
)) {
3425 printf("startup failed\n");
3429 ret
= net_ads_enctype_lookup_account(c
, ads
, argv
[0], &res
, NULL
);
3434 dn
= ads_get_dn(ads
, c
, res
);
3439 etype_list
= ENC_CRC32
| ENC_RSA_MD5
| ENC_RC4_HMAC_MD5
;
3440 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3441 etype_list
|= ENC_HMAC_SHA1_96_AES128
;
3443 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3444 etype_list
|= ENC_HMAC_SHA1_96_AES256
;
3447 if (argv
[1] != NULL
) {
3448 sscanf(argv
[1], "%i", &etype_list
);
3451 etype_list_str
= talloc_asprintf(c
, "%d", etype_list
);
3452 if (!etype_list_str
) {
3456 mods
= ads_init_mods(c
);
3461 status
= ads_mod_str(c
, &mods
, "msDS-SupportedEncryptionTypes",
3463 if (!ADS_ERR_OK(status
)) {
3467 status
= ads_gen_mod(ads
, dn
, mods
);
3468 if (!ADS_ERR_OK(status
)) {
3469 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3470 ads_errstr(status
));
3474 ads_msgfree(ads
, res
);
3476 ret
= net_ads_enctype_lookup_account(c
, ads
, argv
[0], &res
, &str
);
3481 net_ads_enctype_dump_enctypes(argv
[0], str
);
3485 ads_msgfree(ads
, res
);
3491 static int net_ads_enctypes_delete(struct net_context
*c
, int argc
, const char **argv
)
3496 LDAPMessage
*res
= NULL
;
3500 if (c
->display_usage
|| argc
< 1) {
3502 "net ads enctypes delete <sAMAccountName>\n"
3505 _("Delete supported enctypes"));
3509 status
= ads_startup(c
, false, &ads
);
3510 if (!ADS_ERR_OK(status
)) {
3511 printf("startup failed\n");
3515 ret
= net_ads_enctype_lookup_account(c
, ads
, argv
[0], &res
, NULL
);
3520 dn
= ads_get_dn(ads
, c
, res
);
3525 mods
= ads_init_mods(c
);
3530 status
= ads_mod_str(c
, &mods
, "msDS-SupportedEncryptionTypes", NULL
);
3531 if (!ADS_ERR_OK(status
)) {
3535 status
= ads_gen_mod(ads
, dn
, mods
);
3536 if (!ADS_ERR_OK(status
)) {
3537 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3538 ads_errstr(status
));
3545 ads_msgfree(ads
, res
);
3550 static int net_ads_enctypes(struct net_context
*c
, int argc
, const char **argv
)
3552 struct functable func
[] = {
3555 net_ads_enctypes_list
,
3557 N_("List the supported encryption types"),
3558 N_("net ads enctypes list\n"
3559 " List the supported encryption types")
3563 net_ads_enctypes_set
,
3565 N_("Set the supported encryption types"),
3566 N_("net ads enctypes set\n"
3567 " Set the supported encryption types")
3571 net_ads_enctypes_delete
,
3573 N_("Delete the supported encryption types"),
3574 N_("net ads enctypes delete\n"
3575 " Delete the supported encryption types")
3578 {NULL
, NULL
, 0, NULL
, NULL
}
3581 return net_run_function(c
, argc
, argv
, "net ads enctypes", func
);
3585 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
3587 struct functable func
[] = {
3592 N_("Display details on remote ADS server"),
3594 " Display details on remote ADS server")
3600 N_("Join the local machine to ADS realm"),
3602 " Join the local machine to ADS realm")
3608 N_("Validate machine account"),
3609 N_("net ads testjoin\n"
3610 " Validate machine account")
3616 N_("Remove the local machine from ADS"),
3617 N_("net ads leave\n"
3618 " Remove the local machine from ADS")
3624 N_("Display machine account details"),
3625 N_("net ads status\n"
3626 " Display machine account details")
3632 N_("List/modify users"),
3634 " List/modify users")
3640 N_("List/modify groups"),
3641 N_("net ads group\n"
3642 " List/modify groups")
3648 N_("Issue dynamic DNS update"),
3650 " Issue dynamic DNS update")
3656 N_("Change user passwords"),
3657 N_("net ads password\n"
3658 " Change user passwords")
3662 net_ads_changetrustpw
,
3664 N_("Change trust account password"),
3665 N_("net ads changetrustpw\n"
3666 " Change trust account password")
3672 N_("List/modify printer entries"),
3673 N_("net ads printer\n"
3674 " List/modify printer entries")
3680 N_("Issue LDAP search using filter"),
3681 N_("net ads search\n"
3682 " Issue LDAP search using filter")
3688 N_("Issue LDAP search by DN"),
3690 " Issue LDAP search by DN")
3696 N_("Issue LDAP search by SID"),
3698 " Issue LDAP search by SID")
3704 N_("Display workgroup name"),
3705 N_("net ads workgroup\n"
3706 " Display the workgroup name")
3712 N_("Perform CLDAP query on DC"),
3713 N_("net ads lookup\n"
3714 " Find the ADS DC using CLDAP lookups")
3720 N_("Manage local keytab file"),
3721 N_("net ads keytab\n"
3722 " Manage local keytab file")
3728 N_("Manage Service Principal Names (SPN)s"),
3729 N_("net ads spnset\n"
3730 " Manage Service Principal Names (SPN)s")
3736 N_("Manage group policy objects"),
3738 " Manage group policy objects")
3744 N_("Manage kerberos keytab"),
3745 N_("net ads kerberos\n"
3746 " Manage kerberos keytab")
3752 N_("List/modify supported encryption types"),
3753 N_("net ads enctypes\n"
3754 " List/modify enctypes")
3756 {NULL
, NULL
, 0, NULL
, NULL
}
3759 return net_run_function(c
, argc
, argv
, "net ads", func
);
3764 static int net_ads_noads(void)
3766 d_fprintf(stderr
, _("ADS support not compiled in\n"));
3770 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
3772 return net_ads_noads();
3775 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
3777 return net_ads_noads();
3780 int net_ads_setspn(struct net_context
*c
, int argc
, const char **argv
)
3782 return net_ads_noads();
3785 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
3787 return net_ads_noads();
3790 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
3792 return net_ads_noads();
3795 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
3797 return net_ads_noads();
3800 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
3802 return net_ads_noads();
3805 int net_ads_gpo(struct net_context
*c
, int argc
, const char **argv
)
3807 return net_ads_noads();
3810 /* this one shouldn't display a message */
3811 int net_ads_check(struct net_context
*c
)
3816 int net_ads_check_our_domain(struct net_context
*c
)
3821 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
3823 return net_ads_noads();
3826 #endif /* HAVE_ADS */