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 "librpc/gen_ndr/ndr_krb5pac.h"
26 #include "../librpc/gen_ndr/cli_spoolss.h"
27 #include "nsswitch/libwbclient/wbclient.h"
29 #include "libads/cldap.h"
30 #include "libads/dns.h"
31 #include "../libds/common/flags.h"
32 #include "librpc/gen_ndr/libnet_join.h"
33 #include "libnet/libnet_join.h"
40 /* when we do not have sufficient input parameters to contact a remote domain
41 * we always fall back to our own realm - Guenther*/
43 static const char *assume_own_realm(struct net_context
*c
)
45 if (!c
->opt_host
&& strequal(lp_workgroup(), c
->opt_target_workgroup
)) {
53 do a cldap netlogon query
55 static int net_ads_cldap_netlogon(struct net_context
*c
, ADS_STRUCT
*ads
)
57 char addr
[INET6_ADDRSTRLEN
];
58 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
60 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
61 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
62 d_fprintf(stderr
, _("CLDAP query failed!\n"));
66 d_printf(_("Information for Domain Controller: %s\n\n"),
69 d_printf(_("Response Type: "));
70 switch (reply
.command
) {
71 case LOGON_SAM_LOGON_USER_UNKNOWN_EX
:
72 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
74 case LOGON_SAM_LOGON_RESPONSE_EX
:
75 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
78 d_printf("0x%x\n", reply
.command
);
82 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply
.domain_uuid
));
86 "\tIs a GC of the forest: %s\n"
87 "\tIs an LDAP server: %s\n"
89 "\tIs running a KDC: %s\n"
90 "\tIs running time services: %s\n"
91 "\tIs the closest DC: %s\n"
93 "\tHas a hardware clock: %s\n"
94 "\tIs a non-domain NC serviced by LDAP server: %s\n"
95 "\tIs NT6 DC that has some secrets: %s\n"
96 "\tIs NT6 DC that has all secrets: %s\n"),
97 (reply
.server_type
& NBT_SERVER_PDC
) ? _("yes") : _("no"),
98 (reply
.server_type
& NBT_SERVER_GC
) ? _("yes") : _("no"),
99 (reply
.server_type
& NBT_SERVER_LDAP
) ? _("yes") : _("no"),
100 (reply
.server_type
& NBT_SERVER_DS
) ? _("yes") : _("no"),
101 (reply
.server_type
& NBT_SERVER_KDC
) ? _("yes") : _("no"),
102 (reply
.server_type
& NBT_SERVER_TIMESERV
) ? _("yes") : _("no"),
103 (reply
.server_type
& NBT_SERVER_CLOSEST
) ? _("yes") : _("no"),
104 (reply
.server_type
& NBT_SERVER_WRITABLE
) ? _("yes") : _("no"),
105 (reply
.server_type
& NBT_SERVER_GOOD_TIMESERV
) ? _("yes") : _("no"),
106 (reply
.server_type
& NBT_SERVER_NDNC
) ? _("yes") : _("no"),
107 (reply
.server_type
& NBT_SERVER_SELECT_SECRET_DOMAIN_6
) ? _("yes") : _("no"),
108 (reply
.server_type
& NBT_SERVER_FULL_SECRET_DOMAIN_6
) ? _("yes") : _("no"));
111 printf(_("Forest:\t\t\t%s\n"), reply
.forest
);
112 printf(_("Domain:\t\t\t%s\n"), reply
.dns_domain
);
113 printf(_("Domain Controller:\t%s\n"), reply
.pdc_dns_name
);
115 printf(_("Pre-Win2k Domain:\t%s\n"), reply
.domain_name
);
116 printf(_("Pre-Win2k Hostname:\t%s\n"), reply
.pdc_name
);
118 if (*reply
.user_name
) printf(_("User name:\t%s\n"), reply
.user_name
);
120 printf(_("Server Site Name :\t\t%s\n"), reply
.server_site
);
121 printf(_("Client Site Name :\t\t%s\n"), reply
.client_site
);
123 d_printf(_("NT Version: %d\n"), reply
.nt_version
);
124 d_printf(_("LMNT Token: %.2x\n"), reply
.lmnt_token
);
125 d_printf(_("LM20 Token: %.2x\n"), reply
.lm20_token
);
131 this implements the CLDAP based netlogon lookup requests
132 for finding the domain controller of a ADS domain
134 static int net_ads_lookup(struct net_context
*c
, int argc
, const char **argv
)
139 if (c
->display_usage
) {
144 _("Find the ADS DC using CLDAP lookup.\n"));
148 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
149 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
154 if (!ads
->config
.realm
) {
155 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
156 ads
->ldap
.port
= 389;
159 ret
= net_ads_cldap_netlogon(c
, ads
);
166 static int net_ads_info(struct net_context
*c
, int argc
, const char **argv
)
169 char addr
[INET6_ADDRSTRLEN
];
171 if (c
->display_usage
) {
176 _("Display information about an Active Directory "
181 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
182 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
186 if (!ads
|| !ads
->config
.realm
) {
187 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"),
207 http_timestring(talloc_tos(), ads
->config
.current_time
));
209 d_printf(_("KDC server: %s\n"), ads
->auth
.kdc_server
);
210 d_printf(_("Server time offset: %d\n"), ads
->auth
.time_offset
);
216 static void use_in_memory_ccache(void) {
217 /* Use in-memory credentials cache so we do not interfere with
218 * existing credentials */
219 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
222 static ADS_STATUS
ads_startup_int(struct net_context
*c
, bool only_own_domain
,
223 uint32 auth_flags
, ADS_STRUCT
**ads_ret
)
225 ADS_STRUCT
*ads
= NULL
;
227 bool need_password
= false;
228 bool second_time
= false;
230 const char *realm
= NULL
;
231 bool tried_closest_dc
= false;
233 /* lp_realm() should be handled by a command line param,
234 However, the join requires that realm be set in smb.conf
235 and compares our realm with the remote server's so this is
236 ok until someone needs more flexibility */
241 if (only_own_domain
) {
244 realm
= assume_own_realm(c
);
247 ads
= ads_init(realm
, c
->opt_target_workgroup
, c
->opt_host
);
249 if (!c
->opt_user_name
) {
250 c
->opt_user_name
= "administrator";
253 if (c
->opt_user_specified
) {
254 need_password
= true;
258 if (!c
->opt_password
&& need_password
&& !c
->opt_machine_pass
) {
259 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
260 if (!c
->opt_password
) {
262 return ADS_ERROR(LDAP_NO_MEMORY
);
266 if (c
->opt_password
) {
267 use_in_memory_ccache();
268 SAFE_FREE(ads
->auth
.password
);
269 ads
->auth
.password
= smb_xstrdup(c
->opt_password
);
272 ads
->auth
.flags
|= auth_flags
;
273 SAFE_FREE(ads
->auth
.user_name
);
274 ads
->auth
.user_name
= smb_xstrdup(c
->opt_user_name
);
277 * If the username is of the form "name@realm",
278 * extract the realm and convert to upper case.
279 * This is only used to establish the connection.
281 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
283 SAFE_FREE(ads
->auth
.realm
);
284 ads
->auth
.realm
= smb_xstrdup(cp
);
285 strupper_m(ads
->auth
.realm
);
288 status
= ads_connect(ads
);
290 if (!ADS_ERR_OK(status
)) {
292 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
293 NT_STATUS_NO_LOGON_SERVERS
)) {
294 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
299 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
300 need_password
= true;
309 /* when contacting our own domain, make sure we use the closest DC.
310 * This is done by reconnecting to ADS because only the first call to
311 * ads_connect will give us our own sitename */
313 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
315 tried_closest_dc
= true; /* avoid loop */
317 if (!ads_closest_dc(ads
)) {
319 namecache_delete(ads
->server
.realm
, 0x1C);
320 namecache_delete(ads
->server
.workgroup
, 0x1C);
333 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
335 return ads_startup_int(c
, only_own_domain
, 0, ads
);
338 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
340 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
344 Check to see if connection can be made via ads.
345 ads_startup() stores the password in opt_password if it needs to so
346 that rpc or rap can use it without re-prompting.
348 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
353 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
357 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
359 status
= ads_connect(ads
);
360 if ( !ADS_ERR_OK(status
) ) {
368 int net_ads_check_our_domain(struct net_context
*c
)
370 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
373 int net_ads_check(struct net_context
*c
)
375 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
379 determine the netbios workgroup name for a domain
381 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
384 char addr
[INET6_ADDRSTRLEN
];
385 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
387 if (c
->display_usage
) {
389 "net ads workgroup\n"
392 _("Print the workgroup name"));
396 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
397 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
401 if (!ads
->config
.realm
) {
402 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
403 ads
->ldap
.port
= 389;
406 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
407 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
408 d_fprintf(stderr
, _("CLDAP query failed!\n"));
413 d_printf(_("Workgroup: %s\n"), reply
.domain_name
);
422 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
424 char **disp_fields
= (char **) data_area
;
426 if (!field
) { /* must be end of record */
427 if (disp_fields
[0]) {
428 if (!strchr_m(disp_fields
[0], '$')) {
430 d_printf("%-21.21s %s\n",
431 disp_fields
[0], disp_fields
[1]);
433 d_printf("%s\n", disp_fields
[0]);
436 SAFE_FREE(disp_fields
[0]);
437 SAFE_FREE(disp_fields
[1]);
440 if (!values
) /* must be new field, indicate string field */
442 if (StrCaseCmp(field
, "sAMAccountName") == 0) {
443 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
445 if (StrCaseCmp(field
, "description") == 0)
446 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
450 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
452 return net_user_usage(c
, argc
, argv
);
455 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
460 LDAPMessage
*res
=NULL
;
464 if (argc
< 1 || c
->display_usage
)
465 return net_ads_user_usage(c
, argc
, argv
);
467 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
471 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
473 if (!ADS_ERR_OK(status
)) {
474 d_fprintf(stderr
, _("ads_user_add: %s\n"), ads_errstr(status
));
478 if (ads_count_replies(ads
, res
)) {
479 d_fprintf(stderr
, _("ads_user_add: User %s already exists\n"),
484 if (c
->opt_container
) {
485 ou_str
= SMB_STRDUP(c
->opt_container
);
487 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
490 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
492 if (!ADS_ERR_OK(status
)) {
493 d_fprintf(stderr
, _("Could not add user %s: %s\n"), argv
[0],
498 /* if no password is to be set, we're done */
500 d_printf(_("User %s added\n"), argv
[0]);
505 /* try setting the password */
506 if (asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
) == -1) {
509 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
510 ads
->auth
.time_offset
);
512 if (ADS_ERR_OK(status
)) {
513 d_printf(_("User %s added\n"), argv
[0]);
518 /* password didn't set, delete account */
519 d_fprintf(stderr
, _("Could not add user %s. "
520 "Error setting password %s\n"),
521 argv
[0], ads_errstr(status
));
522 ads_msgfree(ads
, res
);
523 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
524 if (ADS_ERR_OK(status
)) {
525 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
526 ads_del_dn(ads
, userdn
);
532 ads_msgfree(ads
, res
);
538 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
540 ADS_STRUCT
*ads
= NULL
;
542 LDAPMessage
*res
= NULL
;
546 const char *attrs
[] = {"memberOf", "primaryGroupID", NULL
};
547 char *searchstring
=NULL
;
551 struct dom_sid primary_group_sid
;
553 enum wbcSidType type
;
555 if (argc
< 1 || c
->display_usage
) {
556 return net_ads_user_usage(c
, argc
, argv
);
559 frame
= talloc_new(talloc_tos());
564 escaped_user
= escape_ldap_string(frame
, argv
[0]);
567 _("ads_user_info: failed to escape user %s\n"),
572 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
577 if (asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
) == -1) {
581 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
582 SAFE_FREE(searchstring
);
584 if (!ADS_ERR_OK(rc
)) {
585 d_fprintf(stderr
, _("ads_search: %s\n"), ads_errstr(rc
));
590 if (!ads_pull_uint32(ads
, res
, "primaryGroupID", &group_rid
)) {
591 d_fprintf(stderr
, _("ads_pull_uint32 failed\n"));
596 rc
= ads_domain_sid(ads
, &primary_group_sid
);
597 if (!ADS_ERR_OK(rc
)) {
598 d_fprintf(stderr
, _("ads_domain_sid: %s\n"), ads_errstr(rc
));
603 sid_append_rid(&primary_group_sid
, group_rid
);
605 wbc_status
= wbcLookupSid((struct wbcDomainSid
*)&primary_group_sid
,
606 NULL
, /* don't look up domain */
609 if (!WBC_ERROR_IS_OK(wbc_status
)) {
610 d_fprintf(stderr
, "wbcLookupSid: %s\n",
611 wbcErrorString(wbc_status
));
616 d_printf("%s\n", primary_group
);
618 wbcFreeMemory(primary_group
);
620 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
621 (LDAPMessage
*)res
, "memberOf");
626 for (i
=0;grouplist
[i
];i
++) {
627 groupname
= ldap_explode_dn(grouplist
[i
], 1);
628 d_printf("%s\n", groupname
[0]);
629 ldap_value_free(groupname
);
631 ldap_value_free(grouplist
);
635 if (res
) ads_msgfree(ads
, res
);
636 if (ads
) ads_destroy(&ads
);
641 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
645 LDAPMessage
*res
= NULL
;
649 return net_ads_user_usage(c
, argc
, argv
);
652 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
656 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
657 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
658 d_printf(_("User %s does not exist.\n"), argv
[0]);
659 ads_msgfree(ads
, res
);
663 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
664 ads_msgfree(ads
, res
);
665 rc
= ads_del_dn(ads
, userdn
);
667 if (ADS_ERR_OK(rc
)) {
668 d_printf(_("User %s deleted\n"), argv
[0]);
672 d_fprintf(stderr
, _("Error deleting user %s: %s\n"), argv
[0],
678 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
680 struct functable func
[] = {
685 N_("Add an AD user"),
686 N_("net ads user add\n"
693 N_("Display information about an AD user"),
694 N_("net ads user info\n"
695 " Display information about an AD user")
701 N_("Delete an AD user"),
702 N_("net ads user delete\n"
703 " Delete an AD user")
705 {NULL
, NULL
, 0, NULL
, NULL
}
709 const char *shortattrs
[] = {"sAMAccountName", NULL
};
710 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
711 char *disp_fields
[2] = {NULL
, NULL
};
714 if (c
->display_usage
) {
720 net_display_usage_from_functable(func
);
724 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
728 if (c
->opt_long_list_entries
)
729 d_printf(_("\nUser name Comment"
730 "\n-----------------------------\n"));
732 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
734 "(objectCategory=user)",
735 c
->opt_long_list_entries
? longattrs
:
736 shortattrs
, usergrp_display
,
739 return ADS_ERR_OK(rc
) ? 0 : -1;
742 return net_run_function(c
, argc
, argv
, "net ads user", func
);
745 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
747 return net_group_usage(c
, argc
, argv
);
750 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
754 LDAPMessage
*res
=NULL
;
758 if (argc
< 1 || c
->display_usage
) {
759 return net_ads_group_usage(c
, argc
, argv
);
762 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
766 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
768 if (!ADS_ERR_OK(status
)) {
769 d_fprintf(stderr
, _("ads_group_add: %s\n"), ads_errstr(status
));
773 if (ads_count_replies(ads
, res
)) {
774 d_fprintf(stderr
, _("ads_group_add: Group %s already exists\n"), argv
[0]);
778 if (c
->opt_container
) {
779 ou_str
= SMB_STRDUP(c
->opt_container
);
781 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
784 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
786 if (ADS_ERR_OK(status
)) {
787 d_printf(_("Group %s added\n"), argv
[0]);
790 d_fprintf(stderr
, _("Could not add group %s: %s\n"), argv
[0],
796 ads_msgfree(ads
, res
);
802 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
806 LDAPMessage
*res
= NULL
;
809 if (argc
< 1 || c
->display_usage
) {
810 return net_ads_group_usage(c
, argc
, argv
);
813 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
817 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
818 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
819 d_printf(_("Group %s does not exist.\n"), argv
[0]);
820 ads_msgfree(ads
, res
);
824 groupdn
= ads_get_dn(ads
, talloc_tos(), res
);
825 ads_msgfree(ads
, res
);
826 rc
= ads_del_dn(ads
, groupdn
);
827 TALLOC_FREE(groupdn
);
828 if (ADS_ERR_OK(rc
)) {
829 d_printf(_("Group %s deleted\n"), argv
[0]);
833 d_fprintf(stderr
, _("Error deleting group %s: %s\n"), argv
[0],
839 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
841 struct functable func
[] = {
846 N_("Add an AD group"),
847 N_("net ads group add\n"
854 N_("Delete an AD group"),
855 N_("net ads group delete\n"
856 " Delete an AD group")
858 {NULL
, NULL
, 0, NULL
, NULL
}
862 const char *shortattrs
[] = {"sAMAccountName", NULL
};
863 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
864 char *disp_fields
[2] = {NULL
, NULL
};
867 if (c
->display_usage
) {
872 _("List AD groups"));
873 net_display_usage_from_functable(func
);
877 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
881 if (c
->opt_long_list_entries
)
882 d_printf(_("\nGroup name Comment"
883 "\n-----------------------------\n"));
884 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
886 "(objectCategory=group)",
887 c
->opt_long_list_entries
? longattrs
:
888 shortattrs
, usergrp_display
,
892 return ADS_ERR_OK(rc
) ? 0 : -1;
894 return net_run_function(c
, argc
, argv
, "net ads group", func
);
897 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
903 if (c
->display_usage
) {
908 _("Display machine account details"));
912 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
916 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
917 if (!ADS_ERR_OK(rc
)) {
918 d_fprintf(stderr
, _("ads_find_machine_acct: %s\n"), ads_errstr(rc
));
923 if (ads_count_replies(ads
, res
) == 0) {
924 d_fprintf(stderr
, _("No machine account for '%s' found\n"), global_myname());
934 /*******************************************************************
935 Leave an AD domain. Windows XP disables the machine account.
936 We'll try the same. The old code would do an LDAP delete.
937 That only worked using the machine creds because added the machine
938 with full control to the computer object's ACL.
939 *******************************************************************/
941 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
944 struct libnet_UnjoinCtx
*r
= NULL
;
947 if (c
->display_usage
) {
952 _("Leave an AD domain"));
957 d_fprintf(stderr
, _("No realm set, are we joined ?\n"));
961 if (!(ctx
= talloc_init("net_ads_leave"))) {
962 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
966 if (!c
->opt_kerberos
) {
967 use_in_memory_ccache();
970 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
971 if (!W_ERROR_IS_OK(werr
)) {
972 d_fprintf(stderr
, _("Could not initialise unjoin context.\n"));
977 r
->in
.use_kerberos
= c
->opt_kerberos
;
978 r
->in
.dc_name
= c
->opt_host
;
979 r
->in
.domain_name
= lp_realm();
980 r
->in
.admin_account
= c
->opt_user_name
;
981 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
982 r
->in
.modify_config
= lp_config_backend_is_registry();
984 /* Try to delete it, but if that fails, disable it. The
985 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
986 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
987 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
988 r
->in
.delete_machine_account
= true;
989 r
->in
.msg_ctx
= c
->msg_ctx
;
991 werr
= libnet_Unjoin(ctx
, r
);
992 if (!W_ERROR_IS_OK(werr
)) {
993 d_printf(_("Failed to leave domain: %s\n"),
994 r
->out
.error_string
? r
->out
.error_string
:
995 get_friendly_werror_msg(werr
));
999 if (r
->out
.deleted_machine_account
) {
1000 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1001 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1005 /* We couldn't delete it - see if the disable succeeded. */
1006 if (r
->out
.disabled_machine_account
) {
1007 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1008 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1013 /* Based on what we requseted, we shouldn't get here, but if
1014 we did, it means the secrets were removed, and therefore
1015 we have left the domain */
1016 d_fprintf(stderr
, _("Machine '%s' Left domain '%s'\n"),
1017 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1023 if (W_ERROR_IS_OK(werr
)) {
1030 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
1032 ADS_STRUCT
*ads
= NULL
;
1035 struct sockaddr_storage dcip
;
1037 if (!secrets_init()) {
1038 DEBUG(1,("Failed to initialise secrets database\n"));
1039 return NT_STATUS_ACCESS_DENIED
;
1042 net_use_krb_machine_account(c
);
1044 get_dc_name(lp_workgroup(), lp_realm(), dc_name
, &dcip
);
1046 status
= ads_startup(c
, true, &ads
);
1047 if (!ADS_ERR_OK(status
)) {
1048 return ads_ntstatus(status
);
1052 return NT_STATUS_OK
;
1056 check that an existing join is OK
1058 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
1061 use_in_memory_ccache();
1063 if (c
->display_usage
) {
1065 "net ads testjoin\n"
1068 _("Test if the existing join is ok"));
1072 /* Display success or failure */
1073 status
= net_ads_join_ok(c
);
1074 if (!NT_STATUS_IS_OK(status
)) {
1075 fprintf(stderr
, _("Join to domain is not valid: %s\n"),
1076 get_friendly_nt_error_msg(status
));
1080 printf(_("Join is OK\n"));
1084 /*******************************************************************
1085 Simple configu checks before beginning the join
1086 ********************************************************************/
1088 static WERROR
check_ads_config( void )
1090 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
1091 d_printf(_("Host is not configured as a member server.\n"));
1092 return WERR_INVALID_DOMAIN_ROLE
;
1095 if (strlen(global_myname()) > 15) {
1096 d_printf(_("Our netbios name can be at most 15 chars long, "
1097 "\"%s\" is %u chars long\n"), global_myname(),
1098 (unsigned int)strlen(global_myname()));
1099 return WERR_INVALID_COMPUTERNAME
;
1102 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1103 d_fprintf(stderr
, _("realm must be set in in %s for ADS "
1104 "join to succeed.\n"), get_dyn_CONFIGFILE());
1105 return WERR_INVALID_PARAM
;
1111 /*******************************************************************
1112 Send a DNS update request
1113 *******************************************************************/
1115 #if defined(WITH_DNS_UPDATES)
1117 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
1118 const char *pszDomainName
, const char *pszHostName
,
1119 const struct sockaddr_storage
*sslist
,
1122 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1123 const char *machine_name
,
1124 const struct sockaddr_storage
*addrs
,
1127 struct dns_rr_ns
*nameservers
= NULL
;
1129 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1132 const char *dnsdomain
= NULL
;
1133 char *root_domain
= NULL
;
1135 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1136 d_printf(_("No DNS domain configured for %s. "
1137 "Unable to perform DNS Update.\n"), machine_name
);
1138 status
= NT_STATUS_INVALID_PARAMETER
;
1143 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
1144 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1145 /* Child domains often do not have NS records. Look
1146 for the NS record for the forest root domain
1147 (rootDomainNamingContext in therootDSE) */
1149 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1150 LDAPMessage
*msg
= NULL
;
1152 ADS_STATUS ads_status
;
1154 if ( !ads
->ldap
.ld
) {
1155 ads_status
= ads_connect( ads
);
1156 if ( !ADS_ERR_OK(ads_status
) ) {
1157 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1162 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1163 "(objectclass=*)", rootname_attrs
, &msg
);
1164 if (!ADS_ERR_OK(ads_status
)) {
1168 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1170 ads_msgfree( ads
, msg
);
1174 root_domain
= ads_build_domain( root_dn
);
1177 ads_msgfree( ads
, msg
);
1179 /* try again for NS servers */
1181 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1183 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1184 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1185 "realm\n", ads
->config
.realm
));
1189 dnsdomain
= root_domain
;
1193 /* Now perform the dns update - we'll try non-secure and if we fail,
1194 we'll follow it up with a secure update */
1196 fstrcpy( dns_server
, nameservers
[0].hostname
);
1198 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1199 if (!ERR_DNS_IS_OK(dns_err
)) {
1200 status
= NT_STATUS_UNSUCCESSFUL
;
1205 SAFE_FREE( root_domain
);
1210 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
)
1213 struct sockaddr_storage
*iplist
= NULL
;
1214 fstring machine_name
;
1217 name_to_fqdn( machine_name
, global_myname() );
1218 strlower_m( machine_name
);
1220 /* Get our ip address (not the 127.0.0.x address but a real ip
1223 num_addrs
= get_my_ip_address( &iplist
);
1224 if ( num_addrs
<= 0 ) {
1225 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1227 return NT_STATUS_INVALID_PARAMETER
;
1230 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1232 SAFE_FREE( iplist
);
1238 /*******************************************************************
1239 ********************************************************************/
1241 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1243 d_printf(_("net ads join [options]\n"
1244 "Valid options:\n"));
1245 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1246 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1247 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1248 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1249 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1250 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1251 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1252 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1253 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1254 " NB: osName and osVer must be specified together for either to take effect.\n"
1255 " Also, the operatingSystemService attribute is also set when along with\n"
1256 " the two other attributes.\n"));
1261 /*******************************************************************
1262 ********************************************************************/
1264 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1266 TALLOC_CTX
*ctx
= NULL
;
1267 struct libnet_JoinCtx
*r
= NULL
;
1268 const char *domain
= lp_realm();
1269 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1270 bool createupn
= false;
1271 const char *machineupn
= NULL
;
1272 const char *create_in_ou
= NULL
;
1274 const char *os_name
= NULL
;
1275 const char *os_version
= NULL
;
1276 bool modify_config
= lp_config_backend_is_registry();
1278 if (c
->display_usage
)
1279 return net_ads_join_usage(c
, argc
, argv
);
1281 if (!modify_config
) {
1283 werr
= check_ads_config();
1284 if (!W_ERROR_IS_OK(werr
)) {
1285 d_fprintf(stderr
, _("Invalid configuration. Exiting....\n"));
1290 if (!(ctx
= talloc_init("net_ads_join"))) {
1291 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
1296 if (!c
->opt_kerberos
) {
1297 use_in_memory_ccache();
1300 werr
= libnet_init_JoinCtx(ctx
, &r
);
1301 if (!W_ERROR_IS_OK(werr
)) {
1305 /* process additional command line args */
1307 for ( i
=0; i
<argc
; i
++ ) {
1308 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1310 machineupn
= get_string_param(argv
[i
]);
1312 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1313 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1314 d_fprintf(stderr
, _("Please supply a valid OU path.\n"));
1315 werr
= WERR_INVALID_PARAM
;
1319 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1320 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1321 d_fprintf(stderr
, _("Please supply a operating system name.\n"));
1322 werr
= WERR_INVALID_PARAM
;
1326 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1327 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1328 d_fprintf(stderr
, _("Please supply a valid operating system version.\n"));
1329 werr
= WERR_INVALID_PARAM
;
1339 d_fprintf(stderr
, _("Please supply a valid domain name\n"));
1340 werr
= WERR_INVALID_PARAM
;
1344 /* Do the domain join here */
1346 r
->in
.domain_name
= domain
;
1347 r
->in
.create_upn
= createupn
;
1348 r
->in
.upn
= machineupn
;
1349 r
->in
.account_ou
= create_in_ou
;
1350 r
->in
.os_name
= os_name
;
1351 r
->in
.os_version
= os_version
;
1352 r
->in
.dc_name
= c
->opt_host
;
1353 r
->in
.admin_account
= c
->opt_user_name
;
1354 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1356 r
->in
.use_kerberos
= c
->opt_kerberos
;
1357 r
->in
.modify_config
= modify_config
;
1358 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1359 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1360 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1361 r
->in
.msg_ctx
= c
->msg_ctx
;
1363 werr
= libnet_Join(ctx
, r
);
1364 if (!W_ERROR_IS_OK(werr
)) {
1368 /* Check the short name of the domain */
1370 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1371 d_printf(_("The workgroup in %s does not match the short\n"
1372 "domain name obtained from the server.\n"
1373 "Using the name [%s] from the server.\n"
1374 "You should set \"workgroup = %s\" in %s.\n"),
1375 get_dyn_CONFIGFILE(), r
->out
.netbios_domain_name
,
1376 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1379 d_printf(_("Using short domain name -- %s\n"), r
->out
.netbios_domain_name
);
1381 if (r
->out
.dns_domain_name
) {
1382 d_printf(_("Joined '%s' to realm '%s'\n"), r
->in
.machine_name
,
1383 r
->out
.dns_domain_name
);
1385 d_printf(_("Joined '%s' to domain '%s'\n"), r
->in
.machine_name
,
1386 r
->out
.netbios_domain_name
);
1389 #if defined(WITH_DNS_UPDATES)
1390 if (r
->out
.domain_is_ad
) {
1391 /* We enter this block with user creds */
1392 ADS_STRUCT
*ads_dns
= NULL
;
1394 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1395 /* kinit with the machine password */
1397 use_in_memory_ccache();
1398 if (asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname()) == -1) {
1401 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1402 r
->out
.netbios_domain_name
, NULL
, NULL
);
1403 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1404 strupper_m(ads_dns
->auth
.realm
);
1405 ads_kinit_password( ads_dns
);
1408 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns( ctx
, ads_dns
)) ) {
1409 d_fprintf( stderr
, _("DNS update failed!\n") );
1412 /* exit from this block using machine creds */
1413 ads_destroy(&ads_dns
);
1422 /* issue an overall failure message at the end. */
1423 d_printf(_("Failed to join domain: %s\n"),
1424 r
&& r
->out
.error_string
? r
->out
.error_string
:
1425 get_friendly_werror_msg(werr
));
1431 /*******************************************************************
1432 ********************************************************************/
1434 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1436 #if defined(WITH_DNS_UPDATES)
1442 talloc_enable_leak_report();
1445 if (argc
> 0 || c
->display_usage
) {
1447 "net ads dns register\n"
1450 _("Register hostname with DNS\n"));
1454 if (!(ctx
= talloc_init("net_ads_dns"))) {
1455 d_fprintf(stderr
, _("Could not initialise talloc context\n"));
1459 status
= ads_startup(c
, true, &ads
);
1460 if ( !ADS_ERR_OK(status
) ) {
1461 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1466 if ( !NT_STATUS_IS_OK(net_update_dns(ctx
, ads
)) ) {
1467 d_fprintf( stderr
, _("DNS update failed!\n") );
1468 ads_destroy( &ads
);
1473 d_fprintf( stderr
, _("Successfully registered hostname with DNS\n") );
1481 _("DNS update support not enabled at compile time!\n"));
1486 #if defined(WITH_DNS_UPDATES)
1487 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1490 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1492 #if defined(WITH_DNS_UPDATES)
1496 talloc_enable_leak_report();
1499 if (argc
!= 2 || c
->display_usage
) {
1504 _("net ads dns gethostbyname <server> <name>\n"),
1505 _(" Look up hostname from the AD\n"
1506 " server\tName server to use\n"
1507 " name\tName to look up\n"));
1511 err
= do_gethostbyname(argv
[0], argv
[1]);
1513 d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err
));
1518 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1520 struct functable func
[] = {
1523 net_ads_dns_register
,
1525 N_("Add host dns entry to AD"),
1526 N_("net ads dns register\n"
1527 " Add host dns entry to AD")
1531 net_ads_dns_gethostbyname
,
1534 N_("net ads dns gethostbyname\n"
1537 {NULL
, NULL
, 0, NULL
, NULL
}
1540 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1543 /*******************************************************************
1544 ********************************************************************/
1546 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1549 "\nnet ads printer search <printer>"
1550 "\n\tsearch for a printer in the directory\n"
1551 "\nnet ads printer info <printer> <server>"
1552 "\n\tlookup info in directory for printer on server"
1553 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1554 "\nnet ads printer publish <printername>"
1555 "\n\tpublish printer in directory"
1556 "\n\t(note: printer name is required)\n"
1557 "\nnet ads printer remove <printername>"
1558 "\n\tremove printer from directory"
1559 "\n\t(note: printer name is required)\n"));
1563 /*******************************************************************
1564 ********************************************************************/
1566 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1570 LDAPMessage
*res
= NULL
;
1572 if (c
->display_usage
) {
1574 "net ads printer search\n"
1577 _("List printers in the AD"));
1581 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1585 rc
= ads_find_printers(ads
, &res
);
1587 if (!ADS_ERR_OK(rc
)) {
1588 d_fprintf(stderr
, _("ads_find_printer: %s\n"), ads_errstr(rc
));
1589 ads_msgfree(ads
, res
);
1594 if (ads_count_replies(ads
, res
) == 0) {
1595 d_fprintf(stderr
, _("No results found\n"));
1596 ads_msgfree(ads
, res
);
1602 ads_msgfree(ads
, res
);
1607 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1611 const char *servername
, *printername
;
1612 LDAPMessage
*res
= NULL
;
1614 if (c
->display_usage
) {
1617 _("net ads printer info [printername [servername]]\n"
1618 " Display printer info from AD\n"
1619 " printername\tPrinter name or wildcard\n"
1620 " servername\tName of the print server\n"));
1624 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1629 printername
= argv
[0];
1635 servername
= argv
[1];
1637 servername
= global_myname();
1640 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1642 if (!ADS_ERR_OK(rc
)) {
1643 d_fprintf(stderr
, _("Server '%s' not found: %s\n"),
1644 servername
, ads_errstr(rc
));
1645 ads_msgfree(ads
, res
);
1650 if (ads_count_replies(ads
, res
) == 0) {
1651 d_fprintf(stderr
, _("Printer '%s' not found\n"), printername
);
1652 ads_msgfree(ads
, res
);
1658 ads_msgfree(ads
, res
);
1664 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1668 const char *servername
, *printername
;
1669 struct cli_state
*cli
= NULL
;
1670 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1671 struct sockaddr_storage server_ss
;
1673 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1674 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1675 char *prt_dn
, *srv_dn
, **srv_cn
;
1676 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1677 LDAPMessage
*res
= NULL
;
1679 if (argc
< 1 || c
->display_usage
) {
1682 _("net ads printer publish <printername> [servername]\n"
1683 " Publish printer in AD\n"
1684 " printername\tName of the printer\n"
1685 " servername\tName of the print server\n"));
1686 talloc_destroy(mem_ctx
);
1690 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1691 talloc_destroy(mem_ctx
);
1695 printername
= argv
[0];
1698 servername
= argv
[1];
1700 servername
= global_myname();
1703 /* Get printer data from SPOOLSS */
1705 resolve_name(servername
, &server_ss
, 0x20, false);
1707 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1710 c
->opt_user_name
, c
->opt_workgroup
,
1711 c
->opt_password
? c
->opt_password
: "",
1712 CLI_FULL_CONNECTION_USE_KERBEROS
,
1715 if (NT_STATUS_IS_ERR(nt_status
)) {
1716 d_fprintf(stderr
, _("Unable to open a connnection to %s to "
1717 "obtain data for %s\n"),
1718 servername
, printername
);
1720 talloc_destroy(mem_ctx
);
1724 /* Publish on AD server */
1726 ads_find_machine_acct(ads
, &res
, servername
);
1728 if (ads_count_replies(ads
, res
) == 0) {
1729 d_fprintf(stderr
, _("Could not find machine account for server "
1733 talloc_destroy(mem_ctx
);
1737 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1738 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1740 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1741 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1742 if (!srv_cn_escaped
|| !printername_escaped
) {
1743 SAFE_FREE(srv_cn_escaped
);
1744 SAFE_FREE(printername_escaped
);
1745 d_fprintf(stderr
, _("Internal error, out of memory!"));
1747 talloc_destroy(mem_ctx
);
1751 if (asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
) == -1) {
1752 SAFE_FREE(srv_cn_escaped
);
1753 SAFE_FREE(printername_escaped
);
1754 d_fprintf(stderr
, _("Internal error, out of memory!"));
1756 talloc_destroy(mem_ctx
);
1760 SAFE_FREE(srv_cn_escaped
);
1761 SAFE_FREE(printername_escaped
);
1763 nt_status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_spoolss
.syntax_id
, &pipe_hnd
);
1764 if (!NT_STATUS_IS_OK(nt_status
)) {
1765 d_fprintf(stderr
, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1769 talloc_destroy(mem_ctx
);
1773 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1777 talloc_destroy(mem_ctx
);
1781 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1782 if (!ADS_ERR_OK(rc
)) {
1783 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1786 talloc_destroy(mem_ctx
);
1790 d_printf("published printer\n");
1793 talloc_destroy(mem_ctx
);
1798 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1802 const char *servername
;
1804 LDAPMessage
*res
= NULL
;
1806 if (argc
< 1 || c
->display_usage
) {
1809 _("net ads printer remove <printername> [servername]\n"
1810 " Remove a printer from the AD\n"
1811 " printername\tName of the printer\n"
1812 " servername\tName of the print server\n"));
1816 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1821 servername
= argv
[1];
1823 servername
= global_myname();
1826 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1828 if (!ADS_ERR_OK(rc
)) {
1829 d_fprintf(stderr
, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc
));
1830 ads_msgfree(ads
, res
);
1835 if (ads_count_replies(ads
, res
) == 0) {
1836 d_fprintf(stderr
, _("Printer '%s' not found\n"), argv
[1]);
1837 ads_msgfree(ads
, res
);
1842 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
1843 ads_msgfree(ads
, res
);
1844 rc
= ads_del_dn(ads
, prt_dn
);
1845 TALLOC_FREE(prt_dn
);
1847 if (!ADS_ERR_OK(rc
)) {
1848 d_fprintf(stderr
, _("ads_del_dn: %s\n"), ads_errstr(rc
));
1857 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
1859 struct functable func
[] = {
1862 net_ads_printer_search
,
1864 N_("Search for a printer"),
1865 N_("net ads printer search\n"
1866 " Search for a printer")
1870 net_ads_printer_info
,
1872 N_("Display printer information"),
1873 N_("net ads printer info\n"
1874 " Display printer information")
1878 net_ads_printer_publish
,
1880 N_("Publish a printer"),
1881 N_("net ads printer publish\n"
1882 " Publish a printer")
1886 net_ads_printer_remove
,
1888 N_("Delete a printer"),
1889 N_("net ads printer remove\n"
1890 " Delete a printer")
1892 {NULL
, NULL
, 0, NULL
, NULL
}
1895 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
1899 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
1902 const char *auth_principal
= c
->opt_user_name
;
1903 const char *auth_password
= c
->opt_password
;
1905 char *new_password
= NULL
;
1910 if (c
->display_usage
) {
1913 _("net ads password <username>\n"
1914 " Change password for user\n"
1915 " username\tName of user to change password for\n"));
1919 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
1920 d_fprintf(stderr
, _("You must supply an administrator "
1921 "username/password\n"));
1926 d_fprintf(stderr
, _("ERROR: You must say which username to "
1927 "change password for\n"));
1932 if (!strchr_m(user
, '@')) {
1933 if (asprintf(&chr
, "%s@%s", argv
[0], lp_realm()) == -1) {
1939 use_in_memory_ccache();
1940 chr
= strchr_m(auth_principal
, '@');
1947 /* use the realm so we can eventually change passwords for users
1948 in realms other than default */
1949 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
1953 /* we don't actually need a full connect, but it's the easy way to
1954 fill in the KDC's addresss */
1957 if (!ads
->config
.realm
) {
1958 d_fprintf(stderr
, _("Didn't find the kerberos server!\n"));
1964 new_password
= (char *)argv
[1];
1966 if (asprintf(&prompt
, _("Enter new password for %s:"), user
) == -1) {
1969 new_password
= getpass(prompt
);
1973 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
1974 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
1975 if (!ADS_ERR_OK(ret
)) {
1976 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
1981 d_printf(_("Password change for %s completed.\n"), user
);
1987 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
1990 char *host_principal
;
1994 if (c
->display_usage
) {
1996 "net ads changetrustpw\n"
1999 _("Change the machine account's trust password"));
2003 if (!secrets_init()) {
2004 DEBUG(1,("Failed to initialise secrets database\n"));
2008 net_use_krb_machine_account(c
);
2010 use_in_memory_ccache();
2012 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2016 fstrcpy(my_name
, global_myname());
2017 strlower_m(my_name
);
2018 if (asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
) == -1) {
2022 d_printf(_("Changing password for principal: %s\n"), host_principal
);
2024 ret
= ads_change_trust_account_password(ads
, host_principal
);
2026 if (!ADS_ERR_OK(ret
)) {
2027 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2029 SAFE_FREE(host_principal
);
2033 d_printf(_("Password change for principal %s succeeded.\n"), host_principal
);
2035 if (USE_SYSTEM_KEYTAB
) {
2036 d_printf(_("Attempting to update system keytab with new password.\n"));
2037 if (ads_keytab_create_default(ads
)) {
2038 d_printf(_("Failed to update system keytab.\n"));
2043 SAFE_FREE(host_principal
);
2049 help for net ads search
2051 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
2054 "\nnet ads search <expression> <attributes...>\n"
2055 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2056 "The expression is a standard LDAP search expression, and the\n"
2057 "attributes are a list of LDAP fields to show in the results.\n\n"
2058 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2060 net_common_flags_usage(c
, argc
, argv
);
2066 general ADS search function. Useful in diagnosing problems in ADS
2068 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
2072 const char *ldap_exp
;
2074 LDAPMessage
*res
= NULL
;
2076 if (argc
< 1 || c
->display_usage
) {
2077 return net_ads_search_usage(c
, argc
, argv
);
2080 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2087 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
2089 ldap_exp
, attrs
, &res
);
2090 if (!ADS_ERR_OK(rc
)) {
2091 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2096 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2098 /* dump the results */
2101 ads_msgfree(ads
, res
);
2109 help for net ads search
2111 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
2114 "\nnet ads dn <dn> <attributes...>\n"
2115 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2116 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2117 "to show in the results\n\n"
2118 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2119 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2121 net_common_flags_usage(c
, argc
, argv
);
2127 general ADS search function. Useful in diagnosing problems in ADS
2129 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
2135 LDAPMessage
*res
= NULL
;
2137 if (argc
< 1 || c
->display_usage
) {
2138 return net_ads_dn_usage(c
, argc
, argv
);
2141 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2148 rc
= ads_do_search_all(ads
, dn
,
2150 "(objectclass=*)", attrs
, &res
);
2151 if (!ADS_ERR_OK(rc
)) {
2152 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2157 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2159 /* dump the results */
2162 ads_msgfree(ads
, res
);
2169 help for net ads sid search
2171 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2174 "\nnet ads sid <sid> <attributes...>\n"
2175 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2176 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2177 "to show in the results\n\n"
2178 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2180 net_common_flags_usage(c
, argc
, argv
);
2186 general ADS search function. Useful in diagnosing problems in ADS
2188 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2192 const char *sid_string
;
2194 LDAPMessage
*res
= NULL
;
2197 if (argc
< 1 || c
->display_usage
) {
2198 return net_ads_sid_usage(c
, argc
, argv
);
2201 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2205 sid_string
= argv
[0];
2208 if (!string_to_sid(&sid
, sid_string
)) {
2209 d_fprintf(stderr
, _("could not convert sid\n"));
2214 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2215 if (!ADS_ERR_OK(rc
)) {
2216 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2221 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2223 /* dump the results */
2226 ads_msgfree(ads
, res
);
2232 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2237 if (c
->display_usage
) {
2239 "net ads keytab flush\n"
2242 _("Delete the whole keytab"));
2246 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2249 ret
= ads_keytab_flush(ads
);
2254 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2260 if (c
->display_usage
) {
2263 _("net ads keytab add <principal> [principal ...]\n"
2264 " Add principals to local keytab\n"
2265 " principal\tKerberos principal to add to "
2270 d_printf(_("Processing principals to add...\n"));
2271 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2274 for (i
= 0; i
< argc
; i
++) {
2275 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2281 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2286 if (c
->display_usage
) {
2288 "net ads keytab create\n"
2291 _("Create new default keytab"));
2295 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2298 ret
= ads_keytab_create_default(ads
);
2303 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2305 const char *keytab
= NULL
;
2307 if (c
->display_usage
) {
2310 _("net ads keytab list [keytab]\n"
2311 " List a local keytab\n"
2312 " keytab\tKeytab to list\n"));
2320 return ads_keytab_list(keytab
);
2324 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2326 struct functable func
[] = {
2331 N_("Add a service principal"),
2332 N_("net ads keytab add\n"
2333 " Add a service principal")
2337 net_ads_keytab_create
,
2339 N_("Create a fresh keytab"),
2340 N_("net ads keytab create\n"
2341 " Create a fresh keytab")
2345 net_ads_keytab_flush
,
2347 N_("Remove all keytab entries"),
2348 N_("net ads keytab flush\n"
2349 " Remove all keytab entries")
2353 net_ads_keytab_list
,
2355 N_("List a keytab"),
2356 N_("net ads keytab list\n"
2359 {NULL
, NULL
, 0, NULL
, NULL
}
2362 if (!USE_KERBEROS_KEYTAB
) {
2363 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2364 "keytab method to use keytab functions.\n"));
2367 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2370 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2374 if (c
->display_usage
) {
2376 "net ads kerberos renew\n"
2379 _("Renew TGT from existing credential cache"));
2383 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2385 d_printf(_("failed to renew kerberos ticket: %s\n"),
2386 error_message(ret
));
2391 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2393 struct PAC_LOGON_INFO
*info
= NULL
;
2394 TALLOC_CTX
*mem_ctx
= NULL
;
2397 const char *impersonate_princ_s
= NULL
;
2399 if (c
->display_usage
) {
2401 "net ads kerberos pac\n"
2404 _("Dump the Kerberos PAC"));
2408 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2414 impersonate_princ_s
= argv
[0];
2417 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2419 status
= kerberos_return_pac(mem_ctx
,
2428 2592000, /* one month */
2429 impersonate_princ_s
,
2431 if (!NT_STATUS_IS_OK(status
)) {
2432 d_printf(_("failed to query kerberos PAC: %s\n"),
2439 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2440 d_printf(_("The Pac: %s\n"), s
);
2445 TALLOC_FREE(mem_ctx
);
2449 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2451 TALLOC_CTX
*mem_ctx
= NULL
;
2455 if (c
->display_usage
) {
2457 "net ads kerberos kinit\n"
2460 _("Get Ticket Granting Ticket (TGT) for the user"));
2464 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2469 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2471 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2479 2592000, /* one month */
2482 d_printf(_("failed to kinit password: %s\n"),
2489 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2491 struct functable func
[] = {
2494 net_ads_kerberos_kinit
,
2496 N_("Retrieve Ticket Granting Ticket (TGT)"),
2497 N_("net ads kerberos kinit\n"
2498 " Receive Ticket Granting Ticket (TGT)")
2502 net_ads_kerberos_renew
,
2504 N_("Renew Ticket Granting Ticket from credential cache"),
2505 N_("net ads kerberos renew\n"
2506 " Renew Ticket Granting Ticket (TGT) from "
2511 net_ads_kerberos_pac
,
2513 N_("Dump Kerberos PAC"),
2514 N_("net ads kerberos pac\n"
2515 " Dump Kerberos PAC")
2517 {NULL
, NULL
, 0, NULL
, NULL
}
2520 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2523 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2525 struct functable func
[] = {
2530 N_("Display details on remote ADS server"),
2532 " Display details on remote ADS server")
2538 N_("Join the local machine to ADS realm"),
2540 " Join the local machine to ADS realm")
2546 N_("Validate machine account"),
2547 N_("net ads testjoin\n"
2548 " Validate machine account")
2554 N_("Remove the local machine from ADS"),
2555 N_("net ads leave\n"
2556 " Remove the local machine from ADS")
2562 N_("Display machine account details"),
2563 N_("net ads status\n"
2564 " Display machine account details")
2570 N_("List/modify users"),
2572 " List/modify users")
2578 N_("List/modify groups"),
2579 N_("net ads group\n"
2580 " List/modify groups")
2586 N_("Issue dynamic DNS update"),
2588 " Issue dynamic DNS update")
2594 N_("Change user passwords"),
2595 N_("net ads password\n"
2596 " Change user passwords")
2600 net_ads_changetrustpw
,
2602 N_("Change trust account password"),
2603 N_("net ads changetrustpw\n"
2604 " Change trust account password")
2610 N_("List/modify printer entries"),
2611 N_("net ads printer\n"
2612 " List/modify printer entries")
2618 N_("Issue LDAP search using filter"),
2619 N_("net ads search\n"
2620 " Issue LDAP search using filter")
2626 N_("Issue LDAP search by DN"),
2628 " Issue LDAP search by DN")
2634 N_("Issue LDAP search by SID"),
2636 " Issue LDAP search by SID")
2642 N_("Display workgroup name"),
2643 N_("net ads workgroup\n"
2644 " Display the workgroup name")
2650 N_("Perfom CLDAP query on DC"),
2651 N_("net ads lookup\n"
2652 " Find the ADS DC using CLDAP lookups")
2658 N_("Manage local keytab file"),
2659 N_("net ads keytab\n"
2660 " Manage local keytab file")
2666 N_("Manage group policy objects"),
2668 " Manage group policy objects")
2674 N_("Manage kerberos keytab"),
2675 N_("net ads kerberos\n"
2676 " Manage kerberos keytab")
2678 {NULL
, NULL
, 0, NULL
, NULL
}
2681 return net_run_function(c
, argc
, argv
, "net ads", func
);
2686 static int net_ads_noads(void)
2688 d_fprintf(stderr
, _("ADS support not compiled in\n"));
2692 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2694 return net_ads_noads();
2697 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2699 return net_ads_noads();
2702 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2704 return net_ads_noads();
2707 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2709 return net_ads_noads();
2712 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2714 return net_ads_noads();
2717 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2719 return net_ads_noads();
2722 int net_ads_gpo(struct net_context
*c
, int argc
, const char **argv
)
2724 return net_ads_noads();
2727 /* this one shouldn't display a message */
2728 int net_ads_check(struct net_context
*c
)
2733 int net_ads_check_our_domain(struct net_context
*c
)
2738 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2740 return net_ads_noads();
2743 #endif /* WITH_ADS */