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 "rpc_client/cli_pipe.h"
26 #include "librpc/gen_ndr/ndr_krb5pac.h"
27 #include "../librpc/gen_ndr/ndr_spoolss.h"
28 #include "nsswitch/libwbclient/wbclient.h"
30 #include "libads/cldap.h"
31 #include "../lib/addns/dnsquery.h"
32 #include "../libds/common/flags.h"
33 #include "librpc/gen_ndr/libnet_join.h"
34 #include "libnet/libnet_join.h"
38 #include "../libcli/security/security.h"
39 #include "libsmb/libsmb.h"
40 #include "lib/param/loadparm.h"
44 /* when we do not have sufficient input parameters to contact a remote domain
45 * we always fall back to our own realm - Guenther*/
47 static const char *assume_own_realm(struct net_context
*c
)
49 if (!c
->opt_host
&& strequal(lp_workgroup(), c
->opt_target_workgroup
)) {
57 do a cldap netlogon query
59 static int net_ads_cldap_netlogon(struct net_context
*c
, ADS_STRUCT
*ads
)
61 char addr
[INET6_ADDRSTRLEN
];
62 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
64 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
66 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads
->ldap
.ss
, ads
->server
.realm
, &reply
) ) {
67 d_fprintf(stderr
, _("CLDAP query failed!\n"));
71 d_printf(_("Information for Domain Controller: %s\n\n"),
74 d_printf(_("Response Type: "));
75 switch (reply
.command
) {
76 case LOGON_SAM_LOGON_USER_UNKNOWN_EX
:
77 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
79 case LOGON_SAM_LOGON_RESPONSE_EX
:
80 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
83 d_printf("0x%x\n", reply
.command
);
87 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply
.domain_uuid
));
91 "\tIs a GC of the forest: %s\n"
92 "\tIs an LDAP server: %s\n"
94 "\tIs running a KDC: %s\n"
95 "\tIs running time services: %s\n"
96 "\tIs the closest DC: %s\n"
98 "\tHas a hardware clock: %s\n"
99 "\tIs a non-domain NC serviced by LDAP server: %s\n"
100 "\tIs NT6 DC that has some secrets: %s\n"
101 "\tIs NT6 DC that has all secrets: %s\n"),
102 (reply
.server_type
& NBT_SERVER_PDC
) ? _("yes") : _("no"),
103 (reply
.server_type
& NBT_SERVER_GC
) ? _("yes") : _("no"),
104 (reply
.server_type
& NBT_SERVER_LDAP
) ? _("yes") : _("no"),
105 (reply
.server_type
& NBT_SERVER_DS
) ? _("yes") : _("no"),
106 (reply
.server_type
& NBT_SERVER_KDC
) ? _("yes") : _("no"),
107 (reply
.server_type
& NBT_SERVER_TIMESERV
) ? _("yes") : _("no"),
108 (reply
.server_type
& NBT_SERVER_CLOSEST
) ? _("yes") : _("no"),
109 (reply
.server_type
& NBT_SERVER_WRITABLE
) ? _("yes") : _("no"),
110 (reply
.server_type
& NBT_SERVER_GOOD_TIMESERV
) ? _("yes") : _("no"),
111 (reply
.server_type
& NBT_SERVER_NDNC
) ? _("yes") : _("no"),
112 (reply
.server_type
& NBT_SERVER_SELECT_SECRET_DOMAIN_6
) ? _("yes") : _("no"),
113 (reply
.server_type
& NBT_SERVER_FULL_SECRET_DOMAIN_6
) ? _("yes") : _("no"));
116 printf(_("Forest:\t\t\t%s\n"), reply
.forest
);
117 printf(_("Domain:\t\t\t%s\n"), reply
.dns_domain
);
118 printf(_("Domain Controller:\t%s\n"), reply
.pdc_dns_name
);
120 printf(_("Pre-Win2k Domain:\t%s\n"), reply
.domain_name
);
121 printf(_("Pre-Win2k Hostname:\t%s\n"), reply
.pdc_name
);
123 if (*reply
.user_name
) printf(_("User name:\t%s\n"), reply
.user_name
);
125 printf(_("Server Site Name :\t\t%s\n"), reply
.server_site
);
126 printf(_("Client Site Name :\t\t%s\n"), reply
.client_site
);
128 d_printf(_("NT Version: %d\n"), reply
.nt_version
);
129 d_printf(_("LMNT Token: %.2x\n"), reply
.lmnt_token
);
130 d_printf(_("LM20 Token: %.2x\n"), reply
.lm20_token
);
136 this implements the CLDAP based netlogon lookup requests
137 for finding the domain controller of a ADS domain
139 static int net_ads_lookup(struct net_context
*c
, int argc
, const char **argv
)
144 if (c
->display_usage
) {
149 _("Find the ADS DC using CLDAP lookup.\n"));
153 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
154 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
159 if (!ads
->config
.realm
) {
160 ads
->config
.realm
= discard_const_p(char, c
->opt_target_workgroup
);
161 ads
->ldap
.port
= 389;
164 ret
= net_ads_cldap_netlogon(c
, ads
);
171 static int net_ads_info(struct net_context
*c
, int argc
, const char **argv
)
174 char addr
[INET6_ADDRSTRLEN
];
176 if (c
->display_usage
) {
181 _("Display information about an Active Directory "
186 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
187 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
191 if (!ads
|| !ads
->config
.realm
) {
192 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
197 /* Try to set the server's current time since we didn't do a full
198 TCP LDAP session initially */
200 if ( !ADS_ERR_OK(ads_current_time( ads
)) ) {
201 d_fprintf( stderr
, _("Failed to get server's current time!\n"));
204 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
206 d_printf(_("LDAP server: %s\n"), addr
);
207 d_printf(_("LDAP server name: %s\n"), ads
->config
.ldap_server_name
);
208 d_printf(_("Realm: %s\n"), ads
->config
.realm
);
209 d_printf(_("Bind Path: %s\n"), ads
->config
.bind_path
);
210 d_printf(_("LDAP port: %d\n"), ads
->ldap
.port
);
211 d_printf(_("Server time: %s\n"),
212 http_timestring(talloc_tos(), ads
->config
.current_time
));
214 d_printf(_("KDC server: %s\n"), ads
->auth
.kdc_server
);
215 d_printf(_("Server time offset: %d\n"), ads
->auth
.time_offset
);
221 static void use_in_memory_ccache(void) {
222 /* Use in-memory credentials cache so we do not interfere with
223 * existing credentials */
224 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
227 static ADS_STATUS
ads_startup_int(struct net_context
*c
, bool only_own_domain
,
228 uint32 auth_flags
, ADS_STRUCT
**ads_ret
)
230 ADS_STRUCT
*ads
= NULL
;
232 bool need_password
= false;
233 bool second_time
= false;
235 const char *realm
= NULL
;
236 bool tried_closest_dc
= false;
238 /* lp_realm() should be handled by a command line param,
239 However, the join requires that realm be set in smb.conf
240 and compares our realm with the remote server's so this is
241 ok until someone needs more flexibility */
246 if (only_own_domain
) {
249 realm
= assume_own_realm(c
);
252 ads
= ads_init(realm
, c
->opt_target_workgroup
, c
->opt_host
);
254 if (!c
->opt_user_name
) {
255 c
->opt_user_name
= "administrator";
258 if (c
->opt_user_specified
) {
259 need_password
= true;
263 if (!c
->opt_password
&& need_password
&& !c
->opt_machine_pass
) {
264 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
265 if (!c
->opt_password
) {
267 return ADS_ERROR(LDAP_NO_MEMORY
);
271 if (c
->opt_password
) {
272 use_in_memory_ccache();
273 SAFE_FREE(ads
->auth
.password
);
274 ads
->auth
.password
= smb_xstrdup(c
->opt_password
);
277 ads
->auth
.flags
|= auth_flags
;
278 SAFE_FREE(ads
->auth
.user_name
);
279 ads
->auth
.user_name
= smb_xstrdup(c
->opt_user_name
);
282 * If the username is of the form "name@realm",
283 * extract the realm and convert to upper case.
284 * This is only used to establish the connection.
286 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
288 SAFE_FREE(ads
->auth
.realm
);
289 ads
->auth
.realm
= smb_xstrdup(cp
);
290 strupper_m(ads
->auth
.realm
);
293 status
= ads_connect(ads
);
295 if (!ADS_ERR_OK(status
)) {
297 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
298 NT_STATUS_NO_LOGON_SERVERS
)) {
299 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
304 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
305 need_password
= true;
314 /* when contacting our own domain, make sure we use the closest DC.
315 * This is done by reconnecting to ADS because only the first call to
316 * ads_connect will give us our own sitename */
318 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
320 tried_closest_dc
= true; /* avoid loop */
322 if (!ads_closest_dc(ads
)) {
324 namecache_delete(ads
->server
.realm
, 0x1C);
325 namecache_delete(ads
->server
.workgroup
, 0x1C);
338 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
340 return ads_startup_int(c
, only_own_domain
, 0, ads
);
343 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
345 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
349 Check to see if connection can be made via ads.
350 ads_startup() stores the password in opt_password if it needs to so
351 that rpc or rap can use it without re-prompting.
353 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
358 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
362 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
364 status
= ads_connect(ads
);
365 if ( !ADS_ERR_OK(status
) ) {
373 int net_ads_check_our_domain(struct net_context
*c
)
375 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
378 int net_ads_check(struct net_context
*c
)
380 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
384 determine the netbios workgroup name for a domain
386 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
389 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
391 if (c
->display_usage
) {
393 "net ads workgroup\n"
396 _("Print the workgroup name"));
400 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
401 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
405 if (!ads
->config
.realm
) {
406 ads
->config
.realm
= discard_const_p(char, c
->opt_target_workgroup
);
407 ads
->ldap
.port
= 389;
410 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads
->ldap
.ss
, ads
->server
.realm
, &reply
) ) {
411 d_fprintf(stderr
, _("CLDAP query failed!\n"));
416 d_printf(_("Workgroup: %s\n"), reply
.domain_name
);
425 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
427 char **disp_fields
= (char **) data_area
;
429 if (!field
) { /* must be end of record */
430 if (disp_fields
[0]) {
431 if (!strchr_m(disp_fields
[0], '$')) {
433 d_printf("%-21.21s %s\n",
434 disp_fields
[0], disp_fields
[1]);
436 d_printf("%s\n", disp_fields
[0]);
439 SAFE_FREE(disp_fields
[0]);
440 SAFE_FREE(disp_fields
[1]);
443 if (!values
) /* must be new field, indicate string field */
445 if (strcasecmp_m(field
, "sAMAccountName") == 0) {
446 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
448 if (strcasecmp_m(field
, "description") == 0)
449 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
453 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
455 return net_user_usage(c
, argc
, argv
);
458 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
463 LDAPMessage
*res
=NULL
;
467 if (argc
< 1 || c
->display_usage
)
468 return net_ads_user_usage(c
, argc
, argv
);
470 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
474 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
476 if (!ADS_ERR_OK(status
)) {
477 d_fprintf(stderr
, _("ads_user_add: %s\n"), ads_errstr(status
));
481 if (ads_count_replies(ads
, res
)) {
482 d_fprintf(stderr
, _("ads_user_add: User %s already exists\n"),
487 if (c
->opt_container
) {
488 ou_str
= SMB_STRDUP(c
->opt_container
);
490 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
493 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
495 if (!ADS_ERR_OK(status
)) {
496 d_fprintf(stderr
, _("Could not add user %s: %s\n"), argv
[0],
501 /* if no password is to be set, we're done */
503 d_printf(_("User %s added\n"), argv
[0]);
508 /* try setting the password */
509 if (asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
) == -1) {
512 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
513 ads
->auth
.time_offset
);
515 if (ADS_ERR_OK(status
)) {
516 d_printf(_("User %s added\n"), argv
[0]);
521 /* password didn't set, delete account */
522 d_fprintf(stderr
, _("Could not add user %s. "
523 "Error setting password %s\n"),
524 argv
[0], ads_errstr(status
));
525 ads_msgfree(ads
, res
);
526 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
527 if (ADS_ERR_OK(status
)) {
528 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
529 ads_del_dn(ads
, userdn
);
535 ads_msgfree(ads
, res
);
541 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
543 ADS_STRUCT
*ads
= NULL
;
545 LDAPMessage
*res
= NULL
;
549 const char *attrs
[] = {"memberOf", "primaryGroupID", NULL
};
550 char *searchstring
=NULL
;
554 struct dom_sid primary_group_sid
;
556 enum wbcSidType type
;
558 if (argc
< 1 || c
->display_usage
) {
559 return net_ads_user_usage(c
, argc
, argv
);
562 frame
= talloc_new(talloc_tos());
567 escaped_user
= escape_ldap_string(frame
, argv
[0]);
570 _("ads_user_info: failed to escape user %s\n"),
575 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
580 if (asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
) == -1) {
584 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
585 SAFE_FREE(searchstring
);
587 if (!ADS_ERR_OK(rc
)) {
588 d_fprintf(stderr
, _("ads_search: %s\n"), ads_errstr(rc
));
593 if (!ads_pull_uint32(ads
, res
, "primaryGroupID", &group_rid
)) {
594 d_fprintf(stderr
, _("ads_pull_uint32 failed\n"));
599 rc
= ads_domain_sid(ads
, &primary_group_sid
);
600 if (!ADS_ERR_OK(rc
)) {
601 d_fprintf(stderr
, _("ads_domain_sid: %s\n"), ads_errstr(rc
));
606 sid_append_rid(&primary_group_sid
, group_rid
);
608 wbc_status
= wbcLookupSid((struct wbcDomainSid
*)&primary_group_sid
,
609 NULL
, /* don't look up domain */
612 if (!WBC_ERROR_IS_OK(wbc_status
)) {
613 d_fprintf(stderr
, "wbcLookupSid: %s\n",
614 wbcErrorString(wbc_status
));
619 d_printf("%s\n", primary_group
);
621 wbcFreeMemory(primary_group
);
623 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
624 (LDAPMessage
*)res
, "memberOf");
629 for (i
=0;grouplist
[i
];i
++) {
630 groupname
= ldap_explode_dn(grouplist
[i
], 1);
631 d_printf("%s\n", groupname
[0]);
632 ldap_value_free(groupname
);
634 ldap_value_free(grouplist
);
638 if (res
) ads_msgfree(ads
, res
);
639 if (ads
) ads_destroy(&ads
);
644 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
648 LDAPMessage
*res
= NULL
;
652 return net_ads_user_usage(c
, argc
, argv
);
655 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
659 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
660 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
661 d_printf(_("User %s does not exist.\n"), argv
[0]);
662 ads_msgfree(ads
, res
);
666 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
667 ads_msgfree(ads
, res
);
668 rc
= ads_del_dn(ads
, userdn
);
670 if (ADS_ERR_OK(rc
)) {
671 d_printf(_("User %s deleted\n"), argv
[0]);
675 d_fprintf(stderr
, _("Error deleting user %s: %s\n"), argv
[0],
681 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
683 struct functable func
[] = {
688 N_("Add an AD user"),
689 N_("net ads user add\n"
696 N_("Display information about an AD user"),
697 N_("net ads user info\n"
698 " Display information about an AD user")
704 N_("Delete an AD user"),
705 N_("net ads user delete\n"
706 " Delete an AD user")
708 {NULL
, NULL
, 0, NULL
, NULL
}
712 const char *shortattrs
[] = {"sAMAccountName", NULL
};
713 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
714 char *disp_fields
[2] = {NULL
, NULL
};
717 if (c
->display_usage
) {
723 net_display_usage_from_functable(func
);
727 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
731 if (c
->opt_long_list_entries
)
732 d_printf(_("\nUser name Comment"
733 "\n-----------------------------\n"));
735 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
737 "(objectCategory=user)",
738 c
->opt_long_list_entries
? longattrs
:
739 shortattrs
, usergrp_display
,
742 return ADS_ERR_OK(rc
) ? 0 : -1;
745 return net_run_function(c
, argc
, argv
, "net ads user", func
);
748 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
750 return net_group_usage(c
, argc
, argv
);
753 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
757 LDAPMessage
*res
=NULL
;
761 if (argc
< 1 || c
->display_usage
) {
762 return net_ads_group_usage(c
, argc
, argv
);
765 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
769 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
771 if (!ADS_ERR_OK(status
)) {
772 d_fprintf(stderr
, _("ads_group_add: %s\n"), ads_errstr(status
));
776 if (ads_count_replies(ads
, res
)) {
777 d_fprintf(stderr
, _("ads_group_add: Group %s already exists\n"), argv
[0]);
781 if (c
->opt_container
) {
782 ou_str
= SMB_STRDUP(c
->opt_container
);
784 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
787 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
789 if (ADS_ERR_OK(status
)) {
790 d_printf(_("Group %s added\n"), argv
[0]);
793 d_fprintf(stderr
, _("Could not add group %s: %s\n"), argv
[0],
799 ads_msgfree(ads
, res
);
805 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
809 LDAPMessage
*res
= NULL
;
812 if (argc
< 1 || c
->display_usage
) {
813 return net_ads_group_usage(c
, argc
, argv
);
816 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
820 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
821 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
822 d_printf(_("Group %s does not exist.\n"), argv
[0]);
823 ads_msgfree(ads
, res
);
827 groupdn
= ads_get_dn(ads
, talloc_tos(), res
);
828 ads_msgfree(ads
, res
);
829 rc
= ads_del_dn(ads
, groupdn
);
830 TALLOC_FREE(groupdn
);
831 if (ADS_ERR_OK(rc
)) {
832 d_printf(_("Group %s deleted\n"), argv
[0]);
836 d_fprintf(stderr
, _("Error deleting group %s: %s\n"), argv
[0],
842 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
844 struct functable func
[] = {
849 N_("Add an AD group"),
850 N_("net ads group add\n"
857 N_("Delete an AD group"),
858 N_("net ads group delete\n"
859 " Delete an AD group")
861 {NULL
, NULL
, 0, NULL
, NULL
}
865 const char *shortattrs
[] = {"sAMAccountName", NULL
};
866 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
867 char *disp_fields
[2] = {NULL
, NULL
};
870 if (c
->display_usage
) {
875 _("List AD groups"));
876 net_display_usage_from_functable(func
);
880 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
884 if (c
->opt_long_list_entries
)
885 d_printf(_("\nGroup name Comment"
886 "\n-----------------------------\n"));
887 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
889 "(objectCategory=group)",
890 c
->opt_long_list_entries
? longattrs
:
891 shortattrs
, usergrp_display
,
895 return ADS_ERR_OK(rc
) ? 0 : -1;
897 return net_run_function(c
, argc
, argv
, "net ads group", func
);
900 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
906 if (c
->display_usage
) {
911 _("Display machine account details"));
915 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
919 rc
= ads_find_machine_acct(ads
, &res
, lp_netbios_name());
920 if (!ADS_ERR_OK(rc
)) {
921 d_fprintf(stderr
, _("ads_find_machine_acct: %s\n"), ads_errstr(rc
));
926 if (ads_count_replies(ads
, res
) == 0) {
927 d_fprintf(stderr
, _("No machine account for '%s' found\n"), lp_netbios_name());
937 /*******************************************************************
938 Leave an AD domain. Windows XP disables the machine account.
939 We'll try the same. The old code would do an LDAP delete.
940 That only worked using the machine creds because added the machine
941 with full control to the computer object's ACL.
942 *******************************************************************/
944 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
947 struct libnet_UnjoinCtx
*r
= NULL
;
950 if (c
->display_usage
) {
955 _("Leave an AD domain"));
960 d_fprintf(stderr
, _("No realm set, are we joined ?\n"));
964 if (!(ctx
= talloc_init("net_ads_leave"))) {
965 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
969 if (!c
->opt_kerberos
) {
970 use_in_memory_ccache();
974 d_fprintf(stderr
, _("Could not initialise message context. "
975 "Try running as root\n"));
979 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
980 if (!W_ERROR_IS_OK(werr
)) {
981 d_fprintf(stderr
, _("Could not initialise unjoin context.\n"));
986 r
->in
.use_kerberos
= c
->opt_kerberos
;
987 r
->in
.dc_name
= c
->opt_host
;
988 r
->in
.domain_name
= lp_realm();
989 r
->in
.admin_account
= c
->opt_user_name
;
990 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
991 r
->in
.modify_config
= lp_config_backend_is_registry();
993 /* Try to delete it, but if that fails, disable it. The
994 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
995 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
996 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
997 r
->in
.delete_machine_account
= true;
998 r
->in
.msg_ctx
= c
->msg_ctx
;
1000 werr
= libnet_Unjoin(ctx
, r
);
1001 if (!W_ERROR_IS_OK(werr
)) {
1002 d_printf(_("Failed to leave domain: %s\n"),
1003 r
->out
.error_string
? r
->out
.error_string
:
1004 get_friendly_werror_msg(werr
));
1008 if (r
->out
.deleted_machine_account
) {
1009 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1010 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1014 /* We couldn't delete it - see if the disable succeeded. */
1015 if (r
->out
.disabled_machine_account
) {
1016 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1017 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1022 /* Based on what we requested, we shouldn't get here, but if
1023 we did, it means the secrets were removed, and therefore
1024 we have left the domain */
1025 d_fprintf(stderr
, _("Machine '%s' Left domain '%s'\n"),
1026 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1032 if (W_ERROR_IS_OK(werr
)) {
1039 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
1041 ADS_STRUCT
*ads
= NULL
;
1044 struct sockaddr_storage dcip
;
1046 if (!secrets_init()) {
1047 DEBUG(1,("Failed to initialise secrets database\n"));
1048 return NT_STATUS_ACCESS_DENIED
;
1051 net_use_krb_machine_account(c
);
1053 get_dc_name(lp_workgroup(), lp_realm(), dc_name
, &dcip
);
1055 status
= ads_startup(c
, true, &ads
);
1056 if (!ADS_ERR_OK(status
)) {
1057 return ads_ntstatus(status
);
1061 return NT_STATUS_OK
;
1065 check that an existing join is OK
1067 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
1070 use_in_memory_ccache();
1072 if (c
->display_usage
) {
1074 "net ads testjoin\n"
1077 _("Test if the existing join is ok"));
1081 /* Display success or failure */
1082 status
= net_ads_join_ok(c
);
1083 if (!NT_STATUS_IS_OK(status
)) {
1084 fprintf(stderr
, _("Join to domain is not valid: %s\n"),
1085 get_friendly_nt_error_msg(status
));
1089 printf(_("Join is OK\n"));
1093 /*******************************************************************
1094 Simple configu checks before beginning the join
1095 ********************************************************************/
1097 static WERROR
check_ads_config( void )
1099 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
1100 d_printf(_("Host is not configured as a member server.\n"));
1101 return WERR_INVALID_DOMAIN_ROLE
;
1104 if (strlen(lp_netbios_name()) > 15) {
1105 d_printf(_("Our netbios name can be at most 15 chars long, "
1106 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1107 (unsigned int)strlen(lp_netbios_name()));
1108 return WERR_INVALID_COMPUTERNAME
;
1111 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1112 d_fprintf(stderr
, _("realm must be set in in %s for ADS "
1113 "join to succeed.\n"), get_dyn_CONFIGFILE());
1114 return WERR_INVALID_PARAM
;
1120 /*******************************************************************
1121 Send a DNS update request
1122 *******************************************************************/
1124 #if defined(WITH_DNS_UPDATES)
1125 #include "../lib/addns/dns.h"
1126 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
1127 const char *pszDomainName
, const char *pszHostName
,
1128 const struct sockaddr_storage
*sslist
,
1131 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1132 const char *machine_name
,
1133 const struct sockaddr_storage
*addrs
,
1136 struct dns_rr_ns
*nameservers
= NULL
;
1137 int ns_count
= 0, i
;
1138 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1141 const char *dns_hosts_file
;
1142 const char *dnsdomain
= NULL
;
1143 char *root_domain
= NULL
;
1145 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1146 d_printf(_("No DNS domain configured for %s. "
1147 "Unable to perform DNS Update.\n"), machine_name
);
1148 status
= NT_STATUS_INVALID_PARAMETER
;
1153 dns_hosts_file
= lp_parm_const_string(-1, "resolv", "host file", NULL
);
1154 status
= ads_dns_lookup_ns(ctx
, dns_hosts_file
,
1155 dnsdomain
, &nameservers
, &ns_count
);
1156 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1157 /* Child domains often do not have NS records. Look
1158 for the NS record for the forest root domain
1159 (rootDomainNamingContext in therootDSE) */
1161 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1162 LDAPMessage
*msg
= NULL
;
1164 ADS_STATUS ads_status
;
1166 if ( !ads
->ldap
.ld
) {
1167 ads_status
= ads_connect( ads
);
1168 if ( !ADS_ERR_OK(ads_status
) ) {
1169 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1174 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1175 "(objectclass=*)", rootname_attrs
, &msg
);
1176 if (!ADS_ERR_OK(ads_status
)) {
1180 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1182 ads_msgfree( ads
, msg
);
1186 root_domain
= ads_build_domain( root_dn
);
1189 ads_msgfree( ads
, msg
);
1191 /* try again for NS servers */
1193 status
= ads_dns_lookup_ns(ctx
, dns_hosts_file
, root_domain
,
1194 &nameservers
, &ns_count
);
1196 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1197 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1198 "realm\n", ads
->config
.realm
));
1202 dnsdomain
= root_domain
;
1206 for (i
=0; i
< ns_count
; i
++) {
1208 status
= NT_STATUS_UNSUCCESSFUL
;
1210 /* Now perform the dns update - we'll try non-secure and if we fail,
1211 we'll follow it up with a secure update */
1213 fstrcpy( dns_server
, nameservers
[i
].hostname
);
1215 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1216 if (ERR_DNS_IS_OK(dns_err
)) {
1217 status
= NT_STATUS_OK
;
1221 if (ERR_DNS_EQUAL(dns_err
, ERROR_DNS_INVALID_NAME_SERVER
) ||
1222 ERR_DNS_EQUAL(dns_err
, ERROR_DNS_CONNECTION_FAILED
) ||
1223 ERR_DNS_EQUAL(dns_err
, ERROR_DNS_SOCKET_ERROR
)) {
1224 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1225 dns_errstr(dns_err
)));
1229 d_printf(_("DNS Update for %s failed: %s\n"),
1230 machine_name
, dns_errstr(dns_err
));
1231 status
= NT_STATUS_UNSUCCESSFUL
;
1237 SAFE_FREE( root_domain
);
1242 static NTSTATUS
net_update_dns_ext(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
,
1243 const char *hostname
,
1244 struct sockaddr_storage
*iplist
,
1247 struct sockaddr_storage
*iplist_alloc
= NULL
;
1248 fstring machine_name
;
1252 fstrcpy(machine_name
, hostname
);
1254 name_to_fqdn( machine_name
, lp_netbios_name() );
1256 strlower_m( machine_name
);
1258 if (num_addrs
== 0 || iplist
== NULL
) {
1260 * Get our ip address
1261 * (not the 127.0.0.x address but a real ip address)
1263 num_addrs
= get_my_ip_address(&iplist_alloc
);
1264 if ( num_addrs
<= 0 ) {
1265 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1266 "non-loopback IP addresses!\n"));
1267 return NT_STATUS_INVALID_PARAMETER
;
1269 iplist
= iplist_alloc
;
1272 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1275 SAFE_FREE(iplist_alloc
);
1279 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
, const char *hostname
)
1283 status
= net_update_dns_ext(mem_ctx
, ads
, hostname
, NULL
, 0);
1289 /*******************************************************************
1290 ********************************************************************/
1292 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1294 d_printf(_("net ads join [options]\n"
1295 "Valid options:\n"));
1296 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1297 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1298 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1299 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1300 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1301 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1302 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1303 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1304 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1305 " NB: osName and osVer must be specified together for either to take effect.\n"
1306 " Also, the operatingSystemService attribute is also set when along with\n"
1307 " the two other attributes.\n"));
1313 static void _net_ads_join_dns_updates(TALLOC_CTX
*ctx
, struct libnet_JoinCtx
*r
)
1315 #if defined(WITH_DNS_UPDATES)
1316 ADS_STRUCT
*ads_dns
= NULL
;
1321 * In a clustered environment, don't do dynamic dns updates:
1322 * Registering the set of ip addresses that are assigned to
1323 * the interfaces of the node that performs the join does usually
1324 * not have the desired effect, since the local interfaces do not
1325 * carry the complete set of the cluster's public IP addresses.
1326 * And it can also contain internal addresses that should not
1327 * be visible to the outside at all.
1328 * In order to do dns updates in a clustererd setup, use
1329 * net ads dns register.
1331 if (lp_clustering()) {
1332 d_fprintf(stderr
, _("Not doing automatic DNS update in a "
1333 "clustered setup.\n"));
1337 if (!r
->out
.domain_is_ad
) {
1342 * We enter this block with user creds.
1343 * kinit with the machine password to do dns update.
1346 ads_dns
= ads_init(lp_realm(), NULL
, r
->in
.dc_name
);
1348 if (ads_dns
== NULL
) {
1349 d_fprintf(stderr
, _("DNS update failed: out of memory!\n"));
1353 use_in_memory_ccache();
1355 ret
= asprintf(&ads_dns
->auth
.user_name
, "%s$", lp_netbios_name());
1357 d_fprintf(stderr
, _("DNS update failed: out of memory\n"));
1361 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1362 r
->out
.netbios_domain_name
, NULL
, NULL
);
1363 if (ads_dns
->auth
.password
== NULL
) {
1364 d_fprintf(stderr
, _("DNS update failed: out of memory\n"));
1368 ads_dns
->auth
.realm
= SMB_STRDUP(r
->out
.dns_domain_name
);
1369 if (ads_dns
->auth
.realm
== NULL
) {
1370 d_fprintf(stderr
, _("DNS update failed: out of memory\n"));
1374 strupper_m(ads_dns
->auth
.realm
);
1376 ret
= ads_kinit_password(ads_dns
);
1379 _("DNS update failed: kinit failed: %s\n"),
1380 error_message(ret
));
1384 status
= net_update_dns(ctx
, ads_dns
, NULL
);
1385 if (!NT_STATUS_IS_OK(status
)) {
1386 d_fprintf( stderr
, _("DNS update failed: %s\n"),
1391 ads_destroy(&ads_dns
);
1398 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1400 TALLOC_CTX
*ctx
= NULL
;
1401 struct libnet_JoinCtx
*r
= NULL
;
1402 const char *domain
= lp_realm();
1403 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1404 bool createupn
= false;
1405 const char *machineupn
= NULL
;
1406 const char *create_in_ou
= NULL
;
1408 const char *os_name
= NULL
;
1409 const char *os_version
= NULL
;
1410 bool modify_config
= lp_config_backend_is_registry();
1412 if (c
->display_usage
)
1413 return net_ads_join_usage(c
, argc
, argv
);
1415 if (!modify_config
) {
1417 werr
= check_ads_config();
1418 if (!W_ERROR_IS_OK(werr
)) {
1419 d_fprintf(stderr
, _("Invalid configuration. Exiting....\n"));
1424 if (!(ctx
= talloc_init("net_ads_join"))) {
1425 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
1430 if (!c
->opt_kerberos
) {
1431 use_in_memory_ccache();
1434 werr
= libnet_init_JoinCtx(ctx
, &r
);
1435 if (!W_ERROR_IS_OK(werr
)) {
1439 /* process additional command line args */
1441 for ( i
=0; i
<argc
; i
++ ) {
1442 if ( !strncasecmp_m(argv
[i
], "createupn", strlen("createupn")) ) {
1444 machineupn
= get_string_param(argv
[i
]);
1446 else if ( !strncasecmp_m(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1447 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1448 d_fprintf(stderr
, _("Please supply a valid OU path.\n"));
1449 werr
= WERR_INVALID_PARAM
;
1453 else if ( !strncasecmp_m(argv
[i
], "osName", strlen("osName")) ) {
1454 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1455 d_fprintf(stderr
, _("Please supply a operating system name.\n"));
1456 werr
= WERR_INVALID_PARAM
;
1460 else if ( !strncasecmp_m(argv
[i
], "osVer", strlen("osVer")) ) {
1461 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1462 d_fprintf(stderr
, _("Please supply a valid operating system version.\n"));
1463 werr
= WERR_INVALID_PARAM
;
1473 d_fprintf(stderr
, _("Please supply a valid domain name\n"));
1474 werr
= WERR_INVALID_PARAM
;
1479 d_fprintf(stderr
, _("Could not initialise message context. "
1480 "Try running as root\n"));
1481 werr
= WERR_ACCESS_DENIED
;
1485 /* Do the domain join here */
1487 r
->in
.domain_name
= domain
;
1488 r
->in
.create_upn
= createupn
;
1489 r
->in
.upn
= machineupn
;
1490 r
->in
.account_ou
= create_in_ou
;
1491 r
->in
.os_name
= os_name
;
1492 r
->in
.os_version
= os_version
;
1493 r
->in
.dc_name
= c
->opt_host
;
1494 r
->in
.admin_account
= c
->opt_user_name
;
1495 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1497 r
->in
.use_kerberos
= c
->opt_kerberos
;
1498 r
->in
.modify_config
= modify_config
;
1499 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1500 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1501 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1502 r
->in
.msg_ctx
= c
->msg_ctx
;
1504 werr
= libnet_Join(ctx
, r
);
1505 if (W_ERROR_EQUAL(werr
, WERR_DCNOTFOUND
) &&
1506 strequal(domain
, lp_realm())) {
1507 r
->in
.domain_name
= lp_workgroup();
1508 werr
= libnet_Join(ctx
, r
);
1510 if (!W_ERROR_IS_OK(werr
)) {
1514 /* Check the short name of the domain */
1516 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1517 d_printf(_("The workgroup in %s does not match the short\n"
1518 "domain name obtained from the server.\n"
1519 "Using the name [%s] from the server.\n"
1520 "You should set \"workgroup = %s\" in %s.\n"),
1521 get_dyn_CONFIGFILE(), r
->out
.netbios_domain_name
,
1522 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1525 d_printf(_("Using short domain name -- %s\n"), r
->out
.netbios_domain_name
);
1527 if (r
->out
.dns_domain_name
) {
1528 d_printf(_("Joined '%s' to realm '%s'\n"), r
->in
.machine_name
,
1529 r
->out
.dns_domain_name
);
1531 d_printf(_("Joined '%s' to domain '%s'\n"), r
->in
.machine_name
,
1532 r
->out
.netbios_domain_name
);
1536 * We try doing the dns update (if it was compiled in).
1537 * If the dns update fails, we still consider the join
1538 * operation as succeeded if we came this far.
1540 _net_ads_join_dns_updates(ctx
, r
);
1548 /* issue an overall failure message at the end. */
1549 d_printf(_("Failed to join domain: %s\n"),
1550 r
&& r
->out
.error_string
? r
->out
.error_string
:
1551 get_friendly_werror_msg(werr
));
1557 /*******************************************************************
1558 ********************************************************************/
1560 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1562 #if defined(WITH_DNS_UPDATES)
1567 const char *hostname
= NULL
;
1568 const char **addrs_list
= NULL
;
1569 struct sockaddr_storage
*addrs
= NULL
;
1574 talloc_enable_leak_report();
1577 if (argc
<= 1 && lp_clustering() && lp_cluster_addresses() == NULL
) {
1578 d_fprintf(stderr
, _("Refusing DNS updates with automatic "
1579 "detection of addresses in a clustered "
1581 c
->display_usage
= true;
1584 if (c
->display_usage
) {
1586 "net ads dns register [hostname [IP [IP...]]]\n"
1589 _("Register hostname with DNS\n"));
1593 if (!(ctx
= talloc_init("net_ads_dns"))) {
1594 d_fprintf(stderr
, _("Could not initialise talloc context\n"));
1603 num_addrs
= argc
- 1;
1604 addrs_list
= &argv
[1];
1605 } else if (lp_clustering()) {
1606 addrs_list
= lp_cluster_addresses();
1607 num_addrs
= str_list_length(addrs_list
);
1610 if (num_addrs
> 0) {
1611 addrs
= talloc_zero_array(ctx
, struct sockaddr_storage
, num_addrs
);
1612 if (addrs
== NULL
) {
1613 d_fprintf(stderr
, _("Error allocating memory!\n"));
1619 for (count
= 0; count
< num_addrs
; count
++) {
1620 if (!interpret_string_addr(&addrs
[count
], addrs_list
[count
], 0)) {
1621 d_fprintf(stderr
, "%s '%s'.\n",
1622 _("Cannot interpret address"),
1629 status
= ads_startup(c
, true, &ads
);
1630 if ( !ADS_ERR_OK(status
) ) {
1631 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1636 ntstatus
= net_update_dns_ext(ctx
, ads
, hostname
, addrs
, num_addrs
);
1637 if (!NT_STATUS_IS_OK(ntstatus
)) {
1638 d_fprintf( stderr
, _("DNS update failed!\n") );
1639 ads_destroy( &ads
);
1644 d_fprintf( stderr
, _("Successfully registered hostname with DNS\n") );
1652 _("DNS update support not enabled at compile time!\n"));
1657 #if defined(WITH_DNS_UPDATES)
1658 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1661 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1663 #if defined(WITH_DNS_UPDATES)
1667 talloc_enable_leak_report();
1670 if (argc
!= 2 || c
->display_usage
) {
1675 _("net ads dns gethostbyname <server> <name>\n"),
1676 _(" Look up hostname from the AD\n"
1677 " server\tName server to use\n"
1678 " name\tName to look up\n"));
1682 err
= do_gethostbyname(argv
[0], argv
[1]);
1684 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1685 dns_errstr(err
), ERROR_DNS_V(err
));
1690 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1692 struct functable func
[] = {
1695 net_ads_dns_register
,
1697 N_("Add host dns entry to AD"),
1698 N_("net ads dns register\n"
1699 " Add host dns entry to AD")
1703 net_ads_dns_gethostbyname
,
1706 N_("net ads dns gethostbyname\n"
1709 {NULL
, NULL
, 0, NULL
, NULL
}
1712 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1715 /*******************************************************************
1716 ********************************************************************/
1718 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1721 "\nnet ads printer search <printer>"
1722 "\n\tsearch for a printer in the directory\n"
1723 "\nnet ads printer info <printer> <server>"
1724 "\n\tlookup info in directory for printer on server"
1725 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1726 "\nnet ads printer publish <printername>"
1727 "\n\tpublish printer in directory"
1728 "\n\t(note: printer name is required)\n"
1729 "\nnet ads printer remove <printername>"
1730 "\n\tremove printer from directory"
1731 "\n\t(note: printer name is required)\n"));
1735 /*******************************************************************
1736 ********************************************************************/
1738 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1742 LDAPMessage
*res
= NULL
;
1744 if (c
->display_usage
) {
1746 "net ads printer search\n"
1749 _("List printers in the AD"));
1753 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1757 rc
= ads_find_printers(ads
, &res
);
1759 if (!ADS_ERR_OK(rc
)) {
1760 d_fprintf(stderr
, _("ads_find_printer: %s\n"), ads_errstr(rc
));
1761 ads_msgfree(ads
, res
);
1766 if (ads_count_replies(ads
, res
) == 0) {
1767 d_fprintf(stderr
, _("No results found\n"));
1768 ads_msgfree(ads
, res
);
1774 ads_msgfree(ads
, res
);
1779 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1783 const char *servername
, *printername
;
1784 LDAPMessage
*res
= NULL
;
1786 if (c
->display_usage
) {
1789 _("net ads printer info [printername [servername]]\n"
1790 " Display printer info from AD\n"
1791 " printername\tPrinter name or wildcard\n"
1792 " servername\tName of the print server\n"));
1796 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1801 printername
= argv
[0];
1807 servername
= argv
[1];
1809 servername
= lp_netbios_name();
1812 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1814 if (!ADS_ERR_OK(rc
)) {
1815 d_fprintf(stderr
, _("Server '%s' not found: %s\n"),
1816 servername
, ads_errstr(rc
));
1817 ads_msgfree(ads
, res
);
1822 if (ads_count_replies(ads
, res
) == 0) {
1823 d_fprintf(stderr
, _("Printer '%s' not found\n"), printername
);
1824 ads_msgfree(ads
, res
);
1830 ads_msgfree(ads
, res
);
1836 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1840 const char *servername
, *printername
;
1841 struct cli_state
*cli
= NULL
;
1842 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1843 struct sockaddr_storage server_ss
;
1845 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1846 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1847 char *prt_dn
, *srv_dn
, **srv_cn
;
1848 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1849 LDAPMessage
*res
= NULL
;
1851 if (argc
< 1 || c
->display_usage
) {
1854 _("net ads printer publish <printername> [servername]\n"
1855 " Publish printer in AD\n"
1856 " printername\tName of the printer\n"
1857 " servername\tName of the print server\n"));
1858 talloc_destroy(mem_ctx
);
1862 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1863 talloc_destroy(mem_ctx
);
1867 printername
= argv
[0];
1870 servername
= argv
[1];
1872 servername
= lp_netbios_name();
1875 /* Get printer data from SPOOLSS */
1877 resolve_name(servername
, &server_ss
, 0x20, false);
1879 nt_status
= cli_full_connection(&cli
, lp_netbios_name(), servername
,
1882 c
->opt_user_name
, c
->opt_workgroup
,
1883 c
->opt_password
? c
->opt_password
: "",
1884 CLI_FULL_CONNECTION_USE_KERBEROS
,
1885 SMB_SIGNING_DEFAULT
);
1887 if (NT_STATUS_IS_ERR(nt_status
)) {
1888 d_fprintf(stderr
, _("Unable to open a connection to %s to "
1889 "obtain data for %s\n"),
1890 servername
, printername
);
1892 talloc_destroy(mem_ctx
);
1896 /* Publish on AD server */
1898 ads_find_machine_acct(ads
, &res
, servername
);
1900 if (ads_count_replies(ads
, res
) == 0) {
1901 d_fprintf(stderr
, _("Could not find machine account for server "
1905 talloc_destroy(mem_ctx
);
1909 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1910 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1912 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1913 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1914 if (!srv_cn_escaped
|| !printername_escaped
) {
1915 SAFE_FREE(srv_cn_escaped
);
1916 SAFE_FREE(printername_escaped
);
1917 d_fprintf(stderr
, _("Internal error, out of memory!"));
1919 talloc_destroy(mem_ctx
);
1923 if (asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
) == -1) {
1924 SAFE_FREE(srv_cn_escaped
);
1925 SAFE_FREE(printername_escaped
);
1926 d_fprintf(stderr
, _("Internal error, out of memory!"));
1928 talloc_destroy(mem_ctx
);
1932 SAFE_FREE(srv_cn_escaped
);
1933 SAFE_FREE(printername_escaped
);
1935 nt_status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_spoolss
.syntax_id
, &pipe_hnd
);
1936 if (!NT_STATUS_IS_OK(nt_status
)) {
1937 d_fprintf(stderr
, _("Unable to open a connection to the spoolss pipe on %s\n"),
1941 talloc_destroy(mem_ctx
);
1945 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1949 talloc_destroy(mem_ctx
);
1953 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1954 if (!ADS_ERR_OK(rc
)) {
1955 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1958 talloc_destroy(mem_ctx
);
1962 d_printf("published printer\n");
1965 talloc_destroy(mem_ctx
);
1970 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1974 const char *servername
;
1976 LDAPMessage
*res
= NULL
;
1978 if (argc
< 1 || c
->display_usage
) {
1981 _("net ads printer remove <printername> [servername]\n"
1982 " Remove a printer from the AD\n"
1983 " printername\tName of the printer\n"
1984 " servername\tName of the print server\n"));
1988 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1993 servername
= argv
[1];
1995 servername
= lp_netbios_name();
1998 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
2000 if (!ADS_ERR_OK(rc
)) {
2001 d_fprintf(stderr
, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc
));
2002 ads_msgfree(ads
, res
);
2007 if (ads_count_replies(ads
, res
) == 0) {
2008 d_fprintf(stderr
, _("Printer '%s' not found\n"), argv
[1]);
2009 ads_msgfree(ads
, res
);
2014 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
2015 ads_msgfree(ads
, res
);
2016 rc
= ads_del_dn(ads
, prt_dn
);
2017 TALLOC_FREE(prt_dn
);
2019 if (!ADS_ERR_OK(rc
)) {
2020 d_fprintf(stderr
, _("ads_del_dn: %s\n"), ads_errstr(rc
));
2029 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
2031 struct functable func
[] = {
2034 net_ads_printer_search
,
2036 N_("Search for a printer"),
2037 N_("net ads printer search\n"
2038 " Search for a printer")
2042 net_ads_printer_info
,
2044 N_("Display printer information"),
2045 N_("net ads printer info\n"
2046 " Display printer information")
2050 net_ads_printer_publish
,
2052 N_("Publish a printer"),
2053 N_("net ads printer publish\n"
2054 " Publish a printer")
2058 net_ads_printer_remove
,
2060 N_("Delete a printer"),
2061 N_("net ads printer remove\n"
2062 " Delete a printer")
2064 {NULL
, NULL
, 0, NULL
, NULL
}
2067 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
2071 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
2074 const char *auth_principal
= c
->opt_user_name
;
2075 const char *auth_password
= c
->opt_password
;
2076 const char *realm
= NULL
;
2077 const char *new_password
= NULL
;
2082 if (c
->display_usage
) {
2085 _("net ads password <username>\n"
2086 " Change password for user\n"
2087 " username\tName of user to change password for\n"));
2091 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
2092 d_fprintf(stderr
, _("You must supply an administrator "
2093 "username/password\n"));
2098 d_fprintf(stderr
, _("ERROR: You must say which username to "
2099 "change password for\n"));
2104 if (!strchr_m(user
, '@')) {
2105 if (asprintf(&chr
, "%s@%s", argv
[0], lp_realm()) == -1) {
2111 use_in_memory_ccache();
2112 chr
= strchr_m(auth_principal
, '@');
2119 /* use the realm so we can eventually change passwords for users
2120 in realms other than default */
2121 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
2125 /* we don't actually need a full connect, but it's the easy way to
2126 fill in the KDC's addresss */
2129 if (!ads
->config
.realm
) {
2130 d_fprintf(stderr
, _("Didn't find the kerberos server!\n"));
2136 new_password
= (const char *)argv
[1];
2138 if (asprintf(&prompt
, _("Enter new password for %s:"), user
) == -1) {
2141 new_password
= getpass(prompt
);
2145 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
2146 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
2147 if (!ADS_ERR_OK(ret
)) {
2148 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2153 d_printf(_("Password change for %s completed.\n"), user
);
2159 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2162 char *host_principal
;
2166 if (c
->display_usage
) {
2168 "net ads changetrustpw\n"
2171 _("Change the machine account's trust password"));
2175 if (!secrets_init()) {
2176 DEBUG(1,("Failed to initialise secrets database\n"));
2180 net_use_krb_machine_account(c
);
2182 use_in_memory_ccache();
2184 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2188 fstrcpy(my_name
, lp_netbios_name());
2189 strlower_m(my_name
);
2190 if (asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
) == -1) {
2194 d_printf(_("Changing password for principal: %s\n"), host_principal
);
2196 ret
= ads_change_trust_account_password(ads
, host_principal
);
2198 if (!ADS_ERR_OK(ret
)) {
2199 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2201 SAFE_FREE(host_principal
);
2205 d_printf(_("Password change for principal %s succeeded.\n"), host_principal
);
2207 if (USE_SYSTEM_KEYTAB
) {
2208 d_printf(_("Attempting to update system keytab with new password.\n"));
2209 if (ads_keytab_create_default(ads
)) {
2210 d_printf(_("Failed to update system keytab.\n"));
2215 SAFE_FREE(host_principal
);
2221 help for net ads search
2223 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
2226 "\nnet ads search <expression> <attributes...>\n"
2227 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2228 "The expression is a standard LDAP search expression, and the\n"
2229 "attributes are a list of LDAP fields to show in the results.\n\n"
2230 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2232 net_common_flags_usage(c
, argc
, argv
);
2238 general ADS search function. Useful in diagnosing problems in ADS
2240 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
2244 const char *ldap_exp
;
2246 LDAPMessage
*res
= NULL
;
2248 if (argc
< 1 || c
->display_usage
) {
2249 return net_ads_search_usage(c
, argc
, argv
);
2252 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2259 rc
= ads_do_search_retry(ads
, ads
->config
.bind_path
,
2261 ldap_exp
, attrs
, &res
);
2262 if (!ADS_ERR_OK(rc
)) {
2263 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2268 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2270 /* dump the results */
2273 ads_msgfree(ads
, res
);
2281 help for net ads search
2283 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
2286 "\nnet ads dn <dn> <attributes...>\n"
2287 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2288 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2289 "to show in the results\n\n"
2290 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2291 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2293 net_common_flags_usage(c
, argc
, argv
);
2299 general ADS search function. Useful in diagnosing problems in ADS
2301 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
2307 LDAPMessage
*res
= NULL
;
2309 if (argc
< 1 || c
->display_usage
) {
2310 return net_ads_dn_usage(c
, argc
, argv
);
2313 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2320 rc
= ads_do_search_all(ads
, dn
,
2322 "(objectclass=*)", attrs
, &res
);
2323 if (!ADS_ERR_OK(rc
)) {
2324 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2329 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2331 /* dump the results */
2334 ads_msgfree(ads
, res
);
2341 help for net ads sid search
2343 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2346 "\nnet ads sid <sid> <attributes...>\n"
2347 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2348 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2349 "to show in the results\n\n"
2350 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2352 net_common_flags_usage(c
, argc
, argv
);
2358 general ADS search function. Useful in diagnosing problems in ADS
2360 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2364 const char *sid_string
;
2366 LDAPMessage
*res
= NULL
;
2369 if (argc
< 1 || c
->display_usage
) {
2370 return net_ads_sid_usage(c
, argc
, argv
);
2373 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2377 sid_string
= argv
[0];
2380 if (!string_to_sid(&sid
, sid_string
)) {
2381 d_fprintf(stderr
, _("could not convert sid\n"));
2386 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2387 if (!ADS_ERR_OK(rc
)) {
2388 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2393 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2395 /* dump the results */
2398 ads_msgfree(ads
, res
);
2404 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2409 if (c
->display_usage
) {
2411 "net ads keytab flush\n"
2414 _("Delete the whole keytab"));
2418 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2421 ret
= ads_keytab_flush(ads
);
2426 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2432 if (c
->display_usage
) {
2435 _("net ads keytab add <principal> [principal ...]\n"
2436 " Add principals to local keytab\n"
2437 " principal\tKerberos principal to add to "
2442 d_printf(_("Processing principals to add...\n"));
2443 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2446 for (i
= 0; i
< argc
; i
++) {
2447 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2453 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2458 if (c
->display_usage
) {
2460 "net ads keytab create\n"
2463 _("Create new default keytab"));
2467 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2470 ret
= ads_keytab_create_default(ads
);
2475 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2477 const char *keytab
= NULL
;
2479 if (c
->display_usage
) {
2482 _("net ads keytab list [keytab]\n"
2483 " List a local keytab\n"
2484 " keytab\tKeytab to list\n"));
2492 return ads_keytab_list(keytab
);
2496 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2498 struct functable func
[] = {
2503 N_("Add a service principal"),
2504 N_("net ads keytab add\n"
2505 " Add a service principal")
2509 net_ads_keytab_create
,
2511 N_("Create a fresh keytab"),
2512 N_("net ads keytab create\n"
2513 " Create a fresh keytab")
2517 net_ads_keytab_flush
,
2519 N_("Remove all keytab entries"),
2520 N_("net ads keytab flush\n"
2521 " Remove all keytab entries")
2525 net_ads_keytab_list
,
2527 N_("List a keytab"),
2528 N_("net ads keytab list\n"
2531 {NULL
, NULL
, 0, NULL
, NULL
}
2534 if (!USE_KERBEROS_KEYTAB
) {
2535 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2536 "keytab method to use keytab functions.\n"));
2539 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2542 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2546 if (c
->display_usage
) {
2548 "net ads kerberos renew\n"
2551 _("Renew TGT from existing credential cache"));
2555 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2557 d_printf(_("failed to renew kerberos ticket: %s\n"),
2558 error_message(ret
));
2563 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2565 struct PAC_LOGON_INFO
*info
= NULL
;
2566 TALLOC_CTX
*mem_ctx
= NULL
;
2569 const char *impersonate_princ_s
= NULL
;
2571 if (c
->display_usage
) {
2573 "net ads kerberos pac\n"
2576 _("Dump the Kerberos PAC"));
2580 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2586 impersonate_princ_s
= argv
[0];
2589 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2591 status
= kerberos_return_pac(mem_ctx
,
2600 2592000, /* one month */
2601 impersonate_princ_s
,
2603 if (!NT_STATUS_IS_OK(status
)) {
2604 d_printf(_("failed to query kerberos PAC: %s\n"),
2611 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2612 d_printf(_("The Pac: %s\n"), s
);
2617 TALLOC_FREE(mem_ctx
);
2621 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2623 TALLOC_CTX
*mem_ctx
= NULL
;
2627 if (c
->display_usage
) {
2629 "net ads kerberos kinit\n"
2632 _("Get Ticket Granting Ticket (TGT) for the user"));
2636 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2641 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2643 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2651 2592000, /* one month */
2654 d_printf(_("failed to kinit password: %s\n"),
2661 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2663 struct functable func
[] = {
2666 net_ads_kerberos_kinit
,
2668 N_("Retrieve Ticket Granting Ticket (TGT)"),
2669 N_("net ads kerberos kinit\n"
2670 " Receive Ticket Granting Ticket (TGT)")
2674 net_ads_kerberos_renew
,
2676 N_("Renew Ticket Granting Ticket from credential cache"),
2677 N_("net ads kerberos renew\n"
2678 " Renew Ticket Granting Ticket (TGT) from "
2683 net_ads_kerberos_pac
,
2685 N_("Dump Kerberos PAC"),
2686 N_("net ads kerberos pac\n"
2687 " Dump Kerberos PAC")
2689 {NULL
, NULL
, 0, NULL
, NULL
}
2692 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2695 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2697 struct functable func
[] = {
2702 N_("Display details on remote ADS server"),
2704 " Display details on remote ADS server")
2710 N_("Join the local machine to ADS realm"),
2712 " Join the local machine to ADS realm")
2718 N_("Validate machine account"),
2719 N_("net ads testjoin\n"
2720 " Validate machine account")
2726 N_("Remove the local machine from ADS"),
2727 N_("net ads leave\n"
2728 " Remove the local machine from ADS")
2734 N_("Display machine account details"),
2735 N_("net ads status\n"
2736 " Display machine account details")
2742 N_("List/modify users"),
2744 " List/modify users")
2750 N_("List/modify groups"),
2751 N_("net ads group\n"
2752 " List/modify groups")
2758 N_("Issue dynamic DNS update"),
2760 " Issue dynamic DNS update")
2766 N_("Change user passwords"),
2767 N_("net ads password\n"
2768 " Change user passwords")
2772 net_ads_changetrustpw
,
2774 N_("Change trust account password"),
2775 N_("net ads changetrustpw\n"
2776 " Change trust account password")
2782 N_("List/modify printer entries"),
2783 N_("net ads printer\n"
2784 " List/modify printer entries")
2790 N_("Issue LDAP search using filter"),
2791 N_("net ads search\n"
2792 " Issue LDAP search using filter")
2798 N_("Issue LDAP search by DN"),
2800 " Issue LDAP search by DN")
2806 N_("Issue LDAP search by SID"),
2808 " Issue LDAP search by SID")
2814 N_("Display workgroup name"),
2815 N_("net ads workgroup\n"
2816 " Display the workgroup name")
2822 N_("Perfom CLDAP query on DC"),
2823 N_("net ads lookup\n"
2824 " Find the ADS DC using CLDAP lookups")
2830 N_("Manage local keytab file"),
2831 N_("net ads keytab\n"
2832 " Manage local keytab file")
2838 N_("Manage group policy objects"),
2840 " Manage group policy objects")
2846 N_("Manage kerberos keytab"),
2847 N_("net ads kerberos\n"
2848 " Manage kerberos keytab")
2850 {NULL
, NULL
, 0, NULL
, NULL
}
2853 return net_run_function(c
, argc
, argv
, "net ads", func
);
2858 static int net_ads_noads(void)
2860 d_fprintf(stderr
, _("ADS support not compiled in\n"));
2864 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2866 return net_ads_noads();
2869 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2871 return net_ads_noads();
2874 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2876 return net_ads_noads();
2879 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2881 return net_ads_noads();
2884 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2886 return net_ads_noads();
2889 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2891 return net_ads_noads();
2894 int net_ads_gpo(struct net_context
*c
, int argc
, const char **argv
)
2896 return net_ads_noads();
2899 /* this one shouldn't display a message */
2900 int net_ads_check(struct net_context
*c
)
2905 int net_ads_check_our_domain(struct net_context
*c
)
2910 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2912 return net_ads_noads();
2915 #endif /* HAVE_ADS */