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"
41 #include "utils/net_dns.h"
45 /* when we do not have sufficient input parameters to contact a remote domain
46 * we always fall back to our own realm - Guenther*/
48 static const char *assume_own_realm(struct net_context
*c
)
50 if (!c
->opt_host
&& strequal(lp_workgroup(), c
->opt_target_workgroup
)) {
58 do a cldap netlogon query
60 static int net_ads_cldap_netlogon(struct net_context
*c
, ADS_STRUCT
*ads
)
62 char addr
[INET6_ADDRSTRLEN
];
63 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
65 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
67 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads
->ldap
.ss
, ads
->server
.realm
, &reply
) ) {
68 d_fprintf(stderr
, _("CLDAP query failed!\n"));
72 d_printf(_("Information for Domain Controller: %s\n\n"),
75 d_printf(_("Response Type: "));
76 switch (reply
.command
) {
77 case LOGON_SAM_LOGON_USER_UNKNOWN_EX
:
78 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
80 case LOGON_SAM_LOGON_RESPONSE_EX
:
81 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
84 d_printf("0x%x\n", reply
.command
);
88 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply
.domain_uuid
));
92 "\tIs a GC of the forest: %s\n"
93 "\tIs an LDAP server: %s\n"
95 "\tIs running a KDC: %s\n"
96 "\tIs running time services: %s\n"
97 "\tIs the closest DC: %s\n"
99 "\tHas a hardware clock: %s\n"
100 "\tIs a non-domain NC serviced by LDAP server: %s\n"
101 "\tIs NT6 DC that has some secrets: %s\n"
102 "\tIs NT6 DC that has all secrets: %s\n"),
103 (reply
.server_type
& NBT_SERVER_PDC
) ? _("yes") : _("no"),
104 (reply
.server_type
& NBT_SERVER_GC
) ? _("yes") : _("no"),
105 (reply
.server_type
& NBT_SERVER_LDAP
) ? _("yes") : _("no"),
106 (reply
.server_type
& NBT_SERVER_DS
) ? _("yes") : _("no"),
107 (reply
.server_type
& NBT_SERVER_KDC
) ? _("yes") : _("no"),
108 (reply
.server_type
& NBT_SERVER_TIMESERV
) ? _("yes") : _("no"),
109 (reply
.server_type
& NBT_SERVER_CLOSEST
) ? _("yes") : _("no"),
110 (reply
.server_type
& NBT_SERVER_WRITABLE
) ? _("yes") : _("no"),
111 (reply
.server_type
& NBT_SERVER_GOOD_TIMESERV
) ? _("yes") : _("no"),
112 (reply
.server_type
& NBT_SERVER_NDNC
) ? _("yes") : _("no"),
113 (reply
.server_type
& NBT_SERVER_SELECT_SECRET_DOMAIN_6
) ? _("yes") : _("no"),
114 (reply
.server_type
& NBT_SERVER_FULL_SECRET_DOMAIN_6
) ? _("yes") : _("no"));
117 printf(_("Forest:\t\t\t%s\n"), reply
.forest
);
118 printf(_("Domain:\t\t\t%s\n"), reply
.dns_domain
);
119 printf(_("Domain Controller:\t%s\n"), reply
.pdc_dns_name
);
121 printf(_("Pre-Win2k Domain:\t%s\n"), reply
.domain_name
);
122 printf(_("Pre-Win2k Hostname:\t%s\n"), reply
.pdc_name
);
124 if (*reply
.user_name
) printf(_("User name:\t%s\n"), reply
.user_name
);
126 printf(_("Server Site Name :\t\t%s\n"), reply
.server_site
);
127 printf(_("Client Site Name :\t\t%s\n"), reply
.client_site
);
129 d_printf(_("NT Version: %d\n"), reply
.nt_version
);
130 d_printf(_("LMNT Token: %.2x\n"), reply
.lmnt_token
);
131 d_printf(_("LM20 Token: %.2x\n"), reply
.lm20_token
);
137 this implements the CLDAP based netlogon lookup requests
138 for finding the domain controller of a ADS domain
140 static int net_ads_lookup(struct net_context
*c
, int argc
, const char **argv
)
145 if (c
->display_usage
) {
150 _("Find the ADS DC using CLDAP lookup.\n"));
154 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
155 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
160 if (!ads
->config
.realm
) {
161 ads
->config
.realm
= discard_const_p(char, c
->opt_target_workgroup
);
162 ads
->ldap
.port
= 389;
165 ret
= net_ads_cldap_netlogon(c
, ads
);
172 static int net_ads_info(struct net_context
*c
, int argc
, const char **argv
)
175 char addr
[INET6_ADDRSTRLEN
];
177 if (c
->display_usage
) {
182 _("Display information about an Active Directory "
187 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
188 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
192 if (!ads
|| !ads
->config
.realm
) {
193 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
198 /* Try to set the server's current time since we didn't do a full
199 TCP LDAP session initially */
201 if ( !ADS_ERR_OK(ads_current_time( ads
)) ) {
202 d_fprintf( stderr
, _("Failed to get server's current time!\n"));
205 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
207 d_printf(_("LDAP server: %s\n"), addr
);
208 d_printf(_("LDAP server name: %s\n"), ads
->config
.ldap_server_name
);
209 d_printf(_("Realm: %s\n"), ads
->config
.realm
);
210 d_printf(_("Bind Path: %s\n"), ads
->config
.bind_path
);
211 d_printf(_("LDAP port: %d\n"), ads
->ldap
.port
);
212 d_printf(_("Server time: %s\n"),
213 http_timestring(talloc_tos(), ads
->config
.current_time
));
215 d_printf(_("KDC server: %s\n"), ads
->auth
.kdc_server
);
216 d_printf(_("Server time offset: %d\n"), ads
->auth
.time_offset
);
222 static void use_in_memory_ccache(void) {
223 /* Use in-memory credentials cache so we do not interfere with
224 * existing credentials */
225 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
228 static ADS_STATUS
ads_startup_int(struct net_context
*c
, bool only_own_domain
,
229 uint32 auth_flags
, ADS_STRUCT
**ads_ret
)
231 ADS_STRUCT
*ads
= NULL
;
233 bool need_password
= false;
234 bool second_time
= false;
236 const char *realm
= NULL
;
237 bool tried_closest_dc
= false;
239 /* lp_realm() should be handled by a command line param,
240 However, the join requires that realm be set in smb.conf
241 and compares our realm with the remote server's so this is
242 ok until someone needs more flexibility */
247 if (only_own_domain
) {
250 realm
= assume_own_realm(c
);
253 ads
= ads_init(realm
, c
->opt_target_workgroup
, c
->opt_host
);
255 if (!c
->opt_user_name
) {
256 c
->opt_user_name
= "administrator";
259 if (c
->opt_user_specified
) {
260 need_password
= true;
264 if (!c
->opt_password
&& need_password
&& !c
->opt_machine_pass
) {
265 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
266 if (!c
->opt_password
) {
268 return ADS_ERROR(LDAP_NO_MEMORY
);
272 if (c
->opt_password
) {
273 use_in_memory_ccache();
274 SAFE_FREE(ads
->auth
.password
);
275 ads
->auth
.password
= smb_xstrdup(c
->opt_password
);
278 ads
->auth
.flags
|= auth_flags
;
279 SAFE_FREE(ads
->auth
.user_name
);
280 ads
->auth
.user_name
= smb_xstrdup(c
->opt_user_name
);
283 * If the username is of the form "name@realm",
284 * extract the realm and convert to upper case.
285 * This is only used to establish the connection.
287 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
289 SAFE_FREE(ads
->auth
.realm
);
290 ads
->auth
.realm
= smb_xstrdup(cp
);
291 if (!strupper_m(ads
->auth
.realm
)) {
293 return ADS_ERROR(LDAP_NO_MEMORY
);
297 status
= ads_connect(ads
);
299 if (!ADS_ERR_OK(status
)) {
301 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
302 NT_STATUS_NO_LOGON_SERVERS
)) {
303 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
308 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
309 need_password
= true;
318 /* when contacting our own domain, make sure we use the closest DC.
319 * This is done by reconnecting to ADS because only the first call to
320 * ads_connect will give us our own sitename */
322 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
324 tried_closest_dc
= true; /* avoid loop */
326 if (!ads_closest_dc(ads
)) {
328 namecache_delete(ads
->server
.realm
, 0x1C);
329 namecache_delete(ads
->server
.workgroup
, 0x1C);
342 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
344 return ads_startup_int(c
, only_own_domain
, 0, ads
);
347 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
349 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
353 Check to see if connection can be made via ads.
354 ads_startup() stores the password in opt_password if it needs to so
355 that rpc or rap can use it without re-prompting.
357 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
362 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
366 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
368 status
= ads_connect(ads
);
369 if ( !ADS_ERR_OK(status
) ) {
377 int net_ads_check_our_domain(struct net_context
*c
)
379 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
382 int net_ads_check(struct net_context
*c
)
384 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
388 determine the netbios workgroup name for a domain
390 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
393 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
395 if (c
->display_usage
) {
397 "net ads workgroup\n"
400 _("Print the workgroup name"));
404 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
405 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
409 if (!ads
->config
.realm
) {
410 ads
->config
.realm
= discard_const_p(char, c
->opt_target_workgroup
);
411 ads
->ldap
.port
= 389;
414 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads
->ldap
.ss
, ads
->server
.realm
, &reply
) ) {
415 d_fprintf(stderr
, _("CLDAP query failed!\n"));
420 d_printf(_("Workgroup: %s\n"), reply
.domain_name
);
429 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
431 char **disp_fields
= (char **) data_area
;
433 if (!field
) { /* must be end of record */
434 if (disp_fields
[0]) {
435 if (!strchr_m(disp_fields
[0], '$')) {
437 d_printf("%-21.21s %s\n",
438 disp_fields
[0], disp_fields
[1]);
440 d_printf("%s\n", disp_fields
[0]);
443 SAFE_FREE(disp_fields
[0]);
444 SAFE_FREE(disp_fields
[1]);
447 if (!values
) /* must be new field, indicate string field */
449 if (strcasecmp_m(field
, "sAMAccountName") == 0) {
450 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
452 if (strcasecmp_m(field
, "description") == 0)
453 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
457 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
459 return net_user_usage(c
, argc
, argv
);
462 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
467 LDAPMessage
*res
=NULL
;
471 if (argc
< 1 || c
->display_usage
)
472 return net_ads_user_usage(c
, argc
, argv
);
474 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
478 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
480 if (!ADS_ERR_OK(status
)) {
481 d_fprintf(stderr
, _("ads_user_add: %s\n"), ads_errstr(status
));
485 if (ads_count_replies(ads
, res
)) {
486 d_fprintf(stderr
, _("ads_user_add: User %s already exists\n"),
491 if (c
->opt_container
) {
492 ou_str
= SMB_STRDUP(c
->opt_container
);
494 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
497 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
499 if (!ADS_ERR_OK(status
)) {
500 d_fprintf(stderr
, _("Could not add user %s: %s\n"), argv
[0],
505 /* if no password is to be set, we're done */
507 d_printf(_("User %s added\n"), argv
[0]);
512 /* try setting the password */
513 if (asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
) == -1) {
516 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
517 ads
->auth
.time_offset
);
519 if (ADS_ERR_OK(status
)) {
520 d_printf(_("User %s added\n"), argv
[0]);
525 /* password didn't set, delete account */
526 d_fprintf(stderr
, _("Could not add user %s. "
527 "Error setting password %s\n"),
528 argv
[0], ads_errstr(status
));
529 ads_msgfree(ads
, res
);
530 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
531 if (ADS_ERR_OK(status
)) {
532 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
533 ads_del_dn(ads
, userdn
);
539 ads_msgfree(ads
, res
);
545 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
547 ADS_STRUCT
*ads
= NULL
;
549 LDAPMessage
*res
= NULL
;
553 const char *attrs
[] = {"memberOf", "primaryGroupID", NULL
};
554 char *searchstring
=NULL
;
558 struct dom_sid primary_group_sid
;
560 enum wbcSidType type
;
562 if (argc
< 1 || c
->display_usage
) {
563 return net_ads_user_usage(c
, argc
, argv
);
566 frame
= talloc_new(talloc_tos());
571 escaped_user
= escape_ldap_string(frame
, argv
[0]);
574 _("ads_user_info: failed to escape user %s\n"),
579 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
584 if (asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
) == -1) {
588 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
589 SAFE_FREE(searchstring
);
591 if (!ADS_ERR_OK(rc
)) {
592 d_fprintf(stderr
, _("ads_search: %s\n"), ads_errstr(rc
));
597 if (!ads_pull_uint32(ads
, res
, "primaryGroupID", &group_rid
)) {
598 d_fprintf(stderr
, _("ads_pull_uint32 failed\n"));
603 rc
= ads_domain_sid(ads
, &primary_group_sid
);
604 if (!ADS_ERR_OK(rc
)) {
605 d_fprintf(stderr
, _("ads_domain_sid: %s\n"), ads_errstr(rc
));
610 sid_append_rid(&primary_group_sid
, group_rid
);
612 wbc_status
= wbcLookupSid((struct wbcDomainSid
*)&primary_group_sid
,
613 NULL
, /* don't look up domain */
616 if (!WBC_ERROR_IS_OK(wbc_status
)) {
617 d_fprintf(stderr
, "wbcLookupSid: %s\n",
618 wbcErrorString(wbc_status
));
623 d_printf("%s\n", primary_group
);
625 wbcFreeMemory(primary_group
);
627 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
628 (LDAPMessage
*)res
, "memberOf");
633 for (i
=0;grouplist
[i
];i
++) {
634 groupname
= ldap_explode_dn(grouplist
[i
], 1);
635 d_printf("%s\n", groupname
[0]);
636 ldap_value_free(groupname
);
638 ldap_value_free(grouplist
);
642 if (res
) ads_msgfree(ads
, res
);
643 if (ads
) ads_destroy(&ads
);
648 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
652 LDAPMessage
*res
= NULL
;
656 return net_ads_user_usage(c
, argc
, argv
);
659 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
663 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
664 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
665 d_printf(_("User %s does not exist.\n"), argv
[0]);
666 ads_msgfree(ads
, res
);
670 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
671 ads_msgfree(ads
, res
);
672 rc
= ads_del_dn(ads
, userdn
);
674 if (ADS_ERR_OK(rc
)) {
675 d_printf(_("User %s deleted\n"), argv
[0]);
679 d_fprintf(stderr
, _("Error deleting user %s: %s\n"), argv
[0],
685 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
687 struct functable func
[] = {
692 N_("Add an AD user"),
693 N_("net ads user add\n"
700 N_("Display information about an AD user"),
701 N_("net ads user info\n"
702 " Display information about an AD user")
708 N_("Delete an AD user"),
709 N_("net ads user delete\n"
710 " Delete an AD user")
712 {NULL
, NULL
, 0, NULL
, NULL
}
716 const char *shortattrs
[] = {"sAMAccountName", NULL
};
717 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
718 char *disp_fields
[2] = {NULL
, NULL
};
721 if (c
->display_usage
) {
727 net_display_usage_from_functable(func
);
731 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
735 if (c
->opt_long_list_entries
)
736 d_printf(_("\nUser name Comment"
737 "\n-----------------------------\n"));
739 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
741 "(objectCategory=user)",
742 c
->opt_long_list_entries
? longattrs
:
743 shortattrs
, usergrp_display
,
746 return ADS_ERR_OK(rc
) ? 0 : -1;
749 return net_run_function(c
, argc
, argv
, "net ads user", func
);
752 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
754 return net_group_usage(c
, argc
, argv
);
757 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
761 LDAPMessage
*res
=NULL
;
765 if (argc
< 1 || c
->display_usage
) {
766 return net_ads_group_usage(c
, argc
, argv
);
769 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
773 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
775 if (!ADS_ERR_OK(status
)) {
776 d_fprintf(stderr
, _("ads_group_add: %s\n"), ads_errstr(status
));
780 if (ads_count_replies(ads
, res
)) {
781 d_fprintf(stderr
, _("ads_group_add: Group %s already exists\n"), argv
[0]);
785 if (c
->opt_container
) {
786 ou_str
= SMB_STRDUP(c
->opt_container
);
788 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
791 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
793 if (ADS_ERR_OK(status
)) {
794 d_printf(_("Group %s added\n"), argv
[0]);
797 d_fprintf(stderr
, _("Could not add group %s: %s\n"), argv
[0],
803 ads_msgfree(ads
, res
);
809 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
813 LDAPMessage
*res
= NULL
;
816 if (argc
< 1 || c
->display_usage
) {
817 return net_ads_group_usage(c
, argc
, argv
);
820 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
824 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
825 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
826 d_printf(_("Group %s does not exist.\n"), argv
[0]);
827 ads_msgfree(ads
, res
);
831 groupdn
= ads_get_dn(ads
, talloc_tos(), res
);
832 ads_msgfree(ads
, res
);
833 rc
= ads_del_dn(ads
, groupdn
);
834 TALLOC_FREE(groupdn
);
835 if (ADS_ERR_OK(rc
)) {
836 d_printf(_("Group %s deleted\n"), argv
[0]);
840 d_fprintf(stderr
, _("Error deleting group %s: %s\n"), argv
[0],
846 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
848 struct functable func
[] = {
853 N_("Add an AD group"),
854 N_("net ads group add\n"
861 N_("Delete an AD group"),
862 N_("net ads group delete\n"
863 " Delete an AD group")
865 {NULL
, NULL
, 0, NULL
, NULL
}
869 const char *shortattrs
[] = {"sAMAccountName", NULL
};
870 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
871 char *disp_fields
[2] = {NULL
, NULL
};
874 if (c
->display_usage
) {
879 _("List AD groups"));
880 net_display_usage_from_functable(func
);
884 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
888 if (c
->opt_long_list_entries
)
889 d_printf(_("\nGroup name Comment"
890 "\n-----------------------------\n"));
891 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
893 "(objectCategory=group)",
894 c
->opt_long_list_entries
? longattrs
:
895 shortattrs
, usergrp_display
,
899 return ADS_ERR_OK(rc
) ? 0 : -1;
901 return net_run_function(c
, argc
, argv
, "net ads group", func
);
904 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
910 if (c
->display_usage
) {
915 _("Display machine account details"));
919 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
923 rc
= ads_find_machine_acct(ads
, &res
, lp_netbios_name());
924 if (!ADS_ERR_OK(rc
)) {
925 d_fprintf(stderr
, _("ads_find_machine_acct: %s\n"), ads_errstr(rc
));
930 if (ads_count_replies(ads
, res
) == 0) {
931 d_fprintf(stderr
, _("No machine account for '%s' found\n"), lp_netbios_name());
941 /*******************************************************************
942 Leave an AD domain. Windows XP disables the machine account.
943 We'll try the same. The old code would do an LDAP delete.
944 That only worked using the machine creds because added the machine
945 with full control to the computer object's ACL.
946 *******************************************************************/
948 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
951 struct libnet_UnjoinCtx
*r
= NULL
;
954 if (c
->display_usage
) {
959 _("Leave an AD domain"));
964 d_fprintf(stderr
, _("No realm set, are we joined ?\n"));
968 if (!(ctx
= talloc_init("net_ads_leave"))) {
969 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
973 if (!c
->opt_kerberos
) {
974 use_in_memory_ccache();
978 d_fprintf(stderr
, _("Could not initialise message context. "
979 "Try running as root\n"));
983 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
984 if (!W_ERROR_IS_OK(werr
)) {
985 d_fprintf(stderr
, _("Could not initialise unjoin context.\n"));
990 r
->in
.use_kerberos
= c
->opt_kerberos
;
991 r
->in
.dc_name
= c
->opt_host
;
992 r
->in
.domain_name
= lp_realm();
993 r
->in
.admin_account
= c
->opt_user_name
;
994 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
995 r
->in
.modify_config
= lp_config_backend_is_registry();
997 /* Try to delete it, but if that fails, disable it. The
998 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
999 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1000 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
1001 r
->in
.delete_machine_account
= true;
1002 r
->in
.msg_ctx
= c
->msg_ctx
;
1004 werr
= libnet_Unjoin(ctx
, r
);
1005 if (!W_ERROR_IS_OK(werr
)) {
1006 d_printf(_("Failed to leave domain: %s\n"),
1007 r
->out
.error_string
? r
->out
.error_string
:
1008 get_friendly_werror_msg(werr
));
1012 if (r
->out
.deleted_machine_account
) {
1013 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1014 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1018 /* We couldn't delete it - see if the disable succeeded. */
1019 if (r
->out
.disabled_machine_account
) {
1020 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1021 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1026 /* Based on what we requested, we shouldn't get here, but if
1027 we did, it means the secrets were removed, and therefore
1028 we have left the domain */
1029 d_fprintf(stderr
, _("Machine '%s' Left domain '%s'\n"),
1030 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1036 if (W_ERROR_IS_OK(werr
)) {
1043 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
1045 ADS_STRUCT
*ads
= NULL
;
1048 struct sockaddr_storage dcip
;
1050 if (!secrets_init()) {
1051 DEBUG(1,("Failed to initialise secrets database\n"));
1052 return NT_STATUS_ACCESS_DENIED
;
1055 net_use_krb_machine_account(c
);
1057 get_dc_name(lp_workgroup(), lp_realm(), dc_name
, &dcip
);
1059 status
= ads_startup(c
, true, &ads
);
1060 if (!ADS_ERR_OK(status
)) {
1061 return ads_ntstatus(status
);
1065 return NT_STATUS_OK
;
1069 check that an existing join is OK
1071 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
1074 use_in_memory_ccache();
1076 if (c
->display_usage
) {
1078 "net ads testjoin\n"
1081 _("Test if the existing join is ok"));
1085 /* Display success or failure */
1086 status
= net_ads_join_ok(c
);
1087 if (!NT_STATUS_IS_OK(status
)) {
1088 fprintf(stderr
, _("Join to domain is not valid: %s\n"),
1089 get_friendly_nt_error_msg(status
));
1093 printf(_("Join is OK\n"));
1097 /*******************************************************************
1098 Simple configu checks before beginning the join
1099 ********************************************************************/
1101 static WERROR
check_ads_config( void )
1103 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
1104 d_printf(_("Host is not configured as a member server.\n"));
1105 return WERR_INVALID_DOMAIN_ROLE
;
1108 if (strlen(lp_netbios_name()) > 15) {
1109 d_printf(_("Our netbios name can be at most 15 chars long, "
1110 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1111 (unsigned int)strlen(lp_netbios_name()));
1112 return WERR_INVALID_COMPUTERNAME
;
1115 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1116 d_fprintf(stderr
, _("realm must be set in in %s for ADS "
1117 "join to succeed.\n"), get_dyn_CONFIGFILE());
1118 return WERR_INVALID_PARAM
;
1124 /*******************************************************************
1125 Send a DNS update request
1126 *******************************************************************/
1128 #if defined(WITH_DNS_UPDATES)
1129 #include "../lib/addns/dns.h"
1131 static NTSTATUS
net_update_dns_internal(struct net_context
*c
,
1132 TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1133 const char *machine_name
,
1134 const struct sockaddr_storage
*addrs
,
1137 struct dns_rr_ns
*nameservers
= NULL
;
1138 int ns_count
= 0, i
;
1139 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1142 const char *dns_hosts_file
;
1143 const char *dnsdomain
= NULL
;
1144 char *root_domain
= NULL
;
1146 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1147 d_printf(_("No DNS domain configured for %s. "
1148 "Unable to perform DNS Update.\n"), machine_name
);
1149 status
= NT_STATUS_INVALID_PARAMETER
;
1154 dns_hosts_file
= lp_parm_const_string(-1, "resolv", "host file", NULL
);
1155 status
= ads_dns_lookup_ns(ctx
, dns_hosts_file
,
1156 dnsdomain
, &nameservers
, &ns_count
);
1157 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1158 /* Child domains often do not have NS records. Look
1159 for the NS record for the forest root domain
1160 (rootDomainNamingContext in therootDSE) */
1162 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1163 LDAPMessage
*msg
= NULL
;
1165 ADS_STATUS ads_status
;
1167 if ( !ads
->ldap
.ld
) {
1168 ads_status
= ads_connect( ads
);
1169 if ( !ADS_ERR_OK(ads_status
) ) {
1170 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1175 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1176 "(objectclass=*)", rootname_attrs
, &msg
);
1177 if (!ADS_ERR_OK(ads_status
)) {
1181 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1183 ads_msgfree( ads
, msg
);
1187 root_domain
= ads_build_domain( root_dn
);
1190 ads_msgfree( ads
, msg
);
1192 /* try again for NS servers */
1194 status
= ads_dns_lookup_ns(ctx
, dns_hosts_file
, root_domain
,
1195 &nameservers
, &ns_count
);
1197 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1198 DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
1199 "realm\n", ads
->config
.realm
));
1203 dnsdomain
= root_domain
;
1207 for (i
=0; i
< ns_count
; i
++) {
1209 uint32_t flags
= DNS_UPDATE_SIGNED
|
1210 DNS_UPDATE_UNSIGNED
|
1211 DNS_UPDATE_UNSIGNED_SUFFICIENT
|
1213 DNS_UPDATE_PROBE_SUFFICIENT
;
1216 flags
&= ~DNS_UPDATE_PROBE_SUFFICIENT
;
1217 flags
&= ~DNS_UPDATE_UNSIGNED_SUFFICIENT
;
1220 status
= NT_STATUS_UNSUCCESSFUL
;
1222 /* Now perform the dns update - we'll try non-secure and if we fail,
1223 we'll follow it up with a secure update */
1225 fstrcpy( dns_server
, nameservers
[i
].hostname
);
1227 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
, flags
);
1228 if (ERR_DNS_IS_OK(dns_err
)) {
1229 status
= NT_STATUS_OK
;
1233 if (ERR_DNS_EQUAL(dns_err
, ERROR_DNS_INVALID_NAME_SERVER
) ||
1234 ERR_DNS_EQUAL(dns_err
, ERROR_DNS_CONNECTION_FAILED
) ||
1235 ERR_DNS_EQUAL(dns_err
, ERROR_DNS_SOCKET_ERROR
)) {
1236 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1237 dns_errstr(dns_err
)));
1241 d_printf(_("DNS Update for %s failed: %s\n"),
1242 machine_name
, dns_errstr(dns_err
));
1243 status
= NT_STATUS_UNSUCCESSFUL
;
1249 SAFE_FREE( root_domain
);
1254 static NTSTATUS
net_update_dns_ext(struct net_context
*c
,
1255 TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
,
1256 const char *hostname
,
1257 struct sockaddr_storage
*iplist
,
1260 struct sockaddr_storage
*iplist_alloc
= NULL
;
1261 fstring machine_name
;
1265 fstrcpy(machine_name
, hostname
);
1267 name_to_fqdn( machine_name
, lp_netbios_name() );
1269 if (!strlower_m( machine_name
)) {
1270 return NT_STATUS_INVALID_PARAMETER
;
1273 if (num_addrs
== 0 || iplist
== NULL
) {
1275 * Get our ip address
1276 * (not the 127.0.0.x address but a real ip address)
1278 num_addrs
= get_my_ip_address(&iplist_alloc
);
1279 if ( num_addrs
<= 0 ) {
1280 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1281 "non-loopback IP addresses!\n"));
1282 return NT_STATUS_INVALID_PARAMETER
;
1284 iplist
= iplist_alloc
;
1287 status
= net_update_dns_internal(c
, mem_ctx
, ads
, machine_name
,
1290 SAFE_FREE(iplist_alloc
);
1294 static NTSTATUS
net_update_dns(struct net_context
*c
, TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
, const char *hostname
)
1298 status
= net_update_dns_ext(c
, mem_ctx
, ads
, hostname
, NULL
, 0);
1304 /*******************************************************************
1305 ********************************************************************/
1307 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1309 d_printf(_("net ads join [options]\n"
1310 "Valid options:\n"));
1311 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1312 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1313 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1314 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1315 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1316 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1317 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1318 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1319 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1320 " NB: osName and osVer must be specified together for either to take effect.\n"
1321 " Also, the operatingSystemService attribute is also set when along with\n"
1322 " the two other attributes.\n"));
1328 static void _net_ads_join_dns_updates(struct net_context
*c
, TALLOC_CTX
*ctx
, struct libnet_JoinCtx
*r
)
1330 #if defined(WITH_DNS_UPDATES)
1331 ADS_STRUCT
*ads_dns
= NULL
;
1336 * In a clustered environment, don't do dynamic dns updates:
1337 * Registering the set of ip addresses that are assigned to
1338 * the interfaces of the node that performs the join does usually
1339 * not have the desired effect, since the local interfaces do not
1340 * carry the complete set of the cluster's public IP addresses.
1341 * And it can also contain internal addresses that should not
1342 * be visible to the outside at all.
1343 * In order to do dns updates in a clustererd setup, use
1344 * net ads dns register.
1346 if (lp_clustering()) {
1347 d_fprintf(stderr
, _("Not doing automatic DNS update in a "
1348 "clustered setup.\n"));
1352 if (!r
->out
.domain_is_ad
) {
1357 * We enter this block with user creds.
1358 * kinit with the machine password to do dns update.
1361 ads_dns
= ads_init(lp_realm(), NULL
, r
->in
.dc_name
);
1363 if (ads_dns
== NULL
) {
1364 d_fprintf(stderr
, _("DNS update failed: out of memory!\n"));
1368 use_in_memory_ccache();
1370 ret
= asprintf(&ads_dns
->auth
.user_name
, "%s$", lp_netbios_name());
1372 d_fprintf(stderr
, _("DNS update failed: out of memory\n"));
1376 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1377 r
->out
.netbios_domain_name
, NULL
, NULL
);
1378 if (ads_dns
->auth
.password
== NULL
) {
1379 d_fprintf(stderr
, _("DNS update failed: out of memory\n"));
1383 ads_dns
->auth
.realm
= SMB_STRDUP(r
->out
.dns_domain_name
);
1384 if (ads_dns
->auth
.realm
== NULL
) {
1385 d_fprintf(stderr
, _("DNS update failed: out of memory\n"));
1389 if (!strupper_m(ads_dns
->auth
.realm
)) {
1390 d_fprintf(stderr
, _("strupper_m %s failed\n"), ads_dns
->auth
.realm
);
1394 ret
= ads_kinit_password(ads_dns
);
1397 _("DNS update failed: kinit failed: %s\n"),
1398 error_message(ret
));
1402 status
= net_update_dns(c
, ctx
, ads_dns
, NULL
);
1403 if (!NT_STATUS_IS_OK(status
)) {
1404 d_fprintf( stderr
, _("DNS update failed: %s\n"),
1409 ads_destroy(&ads_dns
);
1416 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1418 TALLOC_CTX
*ctx
= NULL
;
1419 struct libnet_JoinCtx
*r
= NULL
;
1420 const char *domain
= lp_realm();
1421 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1422 bool createupn
= false;
1423 const char *machineupn
= NULL
;
1424 const char *create_in_ou
= NULL
;
1426 const char *os_name
= NULL
;
1427 const char *os_version
= NULL
;
1428 bool modify_config
= lp_config_backend_is_registry();
1430 if (c
->display_usage
)
1431 return net_ads_join_usage(c
, argc
, argv
);
1433 if (!modify_config
) {
1435 werr
= check_ads_config();
1436 if (!W_ERROR_IS_OK(werr
)) {
1437 d_fprintf(stderr
, _("Invalid configuration. Exiting....\n"));
1442 if (!(ctx
= talloc_init("net_ads_join"))) {
1443 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
1448 if (!c
->opt_kerberos
) {
1449 use_in_memory_ccache();
1452 werr
= libnet_init_JoinCtx(ctx
, &r
);
1453 if (!W_ERROR_IS_OK(werr
)) {
1457 /* process additional command line args */
1459 for ( i
=0; i
<argc
; i
++ ) {
1460 if ( !strncasecmp_m(argv
[i
], "createupn", strlen("createupn")) ) {
1462 machineupn
= get_string_param(argv
[i
]);
1464 else if ( !strncasecmp_m(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1465 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1466 d_fprintf(stderr
, _("Please supply a valid OU path.\n"));
1467 werr
= WERR_INVALID_PARAM
;
1471 else if ( !strncasecmp_m(argv
[i
], "osName", strlen("osName")) ) {
1472 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1473 d_fprintf(stderr
, _("Please supply a operating system name.\n"));
1474 werr
= WERR_INVALID_PARAM
;
1478 else if ( !strncasecmp_m(argv
[i
], "osVer", strlen("osVer")) ) {
1479 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1480 d_fprintf(stderr
, _("Please supply a valid operating system version.\n"));
1481 werr
= WERR_INVALID_PARAM
;
1491 d_fprintf(stderr
, _("Please supply a valid domain name\n"));
1492 werr
= WERR_INVALID_PARAM
;
1497 d_fprintf(stderr
, _("Could not initialise message context. "
1498 "Try running as root\n"));
1499 werr
= WERR_ACCESS_DENIED
;
1503 /* Do the domain join here */
1505 r
->in
.domain_name
= domain
;
1506 r
->in
.create_upn
= createupn
;
1507 r
->in
.upn
= machineupn
;
1508 r
->in
.account_ou
= create_in_ou
;
1509 r
->in
.os_name
= os_name
;
1510 r
->in
.os_version
= os_version
;
1511 r
->in
.dc_name
= c
->opt_host
;
1512 r
->in
.admin_account
= c
->opt_user_name
;
1513 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1515 r
->in
.use_kerberos
= c
->opt_kerberos
;
1516 r
->in
.modify_config
= modify_config
;
1517 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1518 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1519 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1520 r
->in
.msg_ctx
= c
->msg_ctx
;
1522 werr
= libnet_Join(ctx
, r
);
1523 if (W_ERROR_EQUAL(werr
, WERR_DCNOTFOUND
) &&
1524 strequal(domain
, lp_realm())) {
1525 r
->in
.domain_name
= lp_workgroup();
1526 werr
= libnet_Join(ctx
, r
);
1528 if (!W_ERROR_IS_OK(werr
)) {
1532 /* Check the short name of the domain */
1534 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1535 d_printf(_("The workgroup in %s does not match the short\n"
1536 "domain name obtained from the server.\n"
1537 "Using the name [%s] from the server.\n"
1538 "You should set \"workgroup = %s\" in %s.\n"),
1539 get_dyn_CONFIGFILE(), r
->out
.netbios_domain_name
,
1540 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1543 d_printf(_("Using short domain name -- %s\n"), r
->out
.netbios_domain_name
);
1545 if (r
->out
.dns_domain_name
) {
1546 d_printf(_("Joined '%s' to dns domain '%s'\n"), r
->in
.machine_name
,
1547 r
->out
.dns_domain_name
);
1549 d_printf(_("Joined '%s' to domain '%s'\n"), r
->in
.machine_name
,
1550 r
->out
.netbios_domain_name
);
1554 * We try doing the dns update (if it was compiled in).
1555 * If the dns update fails, we still consider the join
1556 * operation as succeeded if we came this far.
1558 _net_ads_join_dns_updates(c
, ctx
, r
);
1566 /* issue an overall failure message at the end. */
1567 d_printf(_("Failed to join domain: %s\n"),
1568 r
&& r
->out
.error_string
? r
->out
.error_string
:
1569 get_friendly_werror_msg(werr
));
1575 /*******************************************************************
1576 ********************************************************************/
1578 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1580 #if defined(WITH_DNS_UPDATES)
1585 const char *hostname
= NULL
;
1586 const char **addrs_list
= NULL
;
1587 struct sockaddr_storage
*addrs
= NULL
;
1592 talloc_enable_leak_report();
1595 if (argc
<= 1 && lp_clustering() && lp_cluster_addresses() == NULL
) {
1596 d_fprintf(stderr
, _("Refusing DNS updates with automatic "
1597 "detection of addresses in a clustered "
1599 c
->display_usage
= true;
1602 if (c
->display_usage
) {
1604 "net ads dns register [hostname [IP [IP...]]]\n"
1607 _("Register hostname with DNS\n"));
1611 if (!(ctx
= talloc_init("net_ads_dns"))) {
1612 d_fprintf(stderr
, _("Could not initialise talloc context\n"));
1621 num_addrs
= argc
- 1;
1622 addrs_list
= &argv
[1];
1623 } else if (lp_clustering()) {
1624 addrs_list
= lp_cluster_addresses();
1625 num_addrs
= str_list_length(addrs_list
);
1628 if (num_addrs
> 0) {
1629 addrs
= talloc_zero_array(ctx
, struct sockaddr_storage
, num_addrs
);
1630 if (addrs
== NULL
) {
1631 d_fprintf(stderr
, _("Error allocating memory!\n"));
1637 for (count
= 0; count
< num_addrs
; count
++) {
1638 if (!interpret_string_addr(&addrs
[count
], addrs_list
[count
], 0)) {
1639 d_fprintf(stderr
, "%s '%s'.\n",
1640 _("Cannot interpret address"),
1647 status
= ads_startup(c
, true, &ads
);
1648 if ( !ADS_ERR_OK(status
) ) {
1649 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1654 ntstatus
= net_update_dns_ext(c
, ctx
, ads
, hostname
, addrs
, num_addrs
);
1655 if (!NT_STATUS_IS_OK(ntstatus
)) {
1656 d_fprintf( stderr
, _("DNS update failed!\n") );
1657 ads_destroy( &ads
);
1662 d_fprintf( stderr
, _("Successfully registered hostname with DNS\n") );
1670 _("DNS update support not enabled at compile time!\n"));
1675 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1677 #if defined(WITH_DNS_UPDATES)
1681 talloc_enable_leak_report();
1684 if (argc
!= 2 || c
->display_usage
) {
1689 _("net ads dns gethostbyname <server> <name>\n"),
1690 _(" Look up hostname from the AD\n"
1691 " server\tName server to use\n"
1692 " name\tName to look up\n"));
1696 err
= do_gethostbyname(argv
[0], argv
[1]);
1698 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1699 dns_errstr(err
), ERROR_DNS_V(err
));
1704 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1706 struct functable func
[] = {
1709 net_ads_dns_register
,
1711 N_("Add host dns entry to AD"),
1712 N_("net ads dns register\n"
1713 " Add host dns entry to AD")
1717 net_ads_dns_gethostbyname
,
1720 N_("net ads dns gethostbyname\n"
1723 {NULL
, NULL
, 0, NULL
, NULL
}
1726 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1729 /*******************************************************************
1730 ********************************************************************/
1732 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1735 "\nnet ads printer search <printer>"
1736 "\n\tsearch for a printer in the directory\n"
1737 "\nnet ads printer info <printer> <server>"
1738 "\n\tlookup info in directory for printer on server"
1739 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1740 "\nnet ads printer publish <printername>"
1741 "\n\tpublish printer in directory"
1742 "\n\t(note: printer name is required)\n"
1743 "\nnet ads printer remove <printername>"
1744 "\n\tremove printer from directory"
1745 "\n\t(note: printer name is required)\n"));
1749 /*******************************************************************
1750 ********************************************************************/
1752 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1756 LDAPMessage
*res
= NULL
;
1758 if (c
->display_usage
) {
1760 "net ads printer search\n"
1763 _("List printers in the AD"));
1767 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1771 rc
= ads_find_printers(ads
, &res
);
1773 if (!ADS_ERR_OK(rc
)) {
1774 d_fprintf(stderr
, _("ads_find_printer: %s\n"), ads_errstr(rc
));
1775 ads_msgfree(ads
, res
);
1780 if (ads_count_replies(ads
, res
) == 0) {
1781 d_fprintf(stderr
, _("No results found\n"));
1782 ads_msgfree(ads
, res
);
1788 ads_msgfree(ads
, res
);
1793 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1797 const char *servername
, *printername
;
1798 LDAPMessage
*res
= NULL
;
1800 if (c
->display_usage
) {
1803 _("net ads printer info [printername [servername]]\n"
1804 " Display printer info from AD\n"
1805 " printername\tPrinter name or wildcard\n"
1806 " servername\tName of the print server\n"));
1810 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1815 printername
= argv
[0];
1821 servername
= argv
[1];
1823 servername
= lp_netbios_name();
1826 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1828 if (!ADS_ERR_OK(rc
)) {
1829 d_fprintf(stderr
, _("Server '%s' not found: %s\n"),
1830 servername
, ads_errstr(rc
));
1831 ads_msgfree(ads
, res
);
1836 if (ads_count_replies(ads
, res
) == 0) {
1837 d_fprintf(stderr
, _("Printer '%s' not found\n"), printername
);
1838 ads_msgfree(ads
, res
);
1844 ads_msgfree(ads
, res
);
1850 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1854 const char *servername
, *printername
;
1855 struct cli_state
*cli
= NULL
;
1856 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1857 struct sockaddr_storage server_ss
;
1859 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1860 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1861 char *prt_dn
, *srv_dn
, **srv_cn
;
1862 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1863 LDAPMessage
*res
= NULL
;
1865 if (argc
< 1 || c
->display_usage
) {
1868 _("net ads printer publish <printername> [servername]\n"
1869 " Publish printer in AD\n"
1870 " printername\tName of the printer\n"
1871 " servername\tName of the print server\n"));
1872 talloc_destroy(mem_ctx
);
1876 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1877 talloc_destroy(mem_ctx
);
1881 printername
= argv
[0];
1884 servername
= argv
[1];
1886 servername
= lp_netbios_name();
1889 /* Get printer data from SPOOLSS */
1891 resolve_name(servername
, &server_ss
, 0x20, false);
1893 nt_status
= cli_full_connection(&cli
, lp_netbios_name(), servername
,
1896 c
->opt_user_name
, c
->opt_workgroup
,
1897 c
->opt_password
? c
->opt_password
: "",
1898 CLI_FULL_CONNECTION_USE_KERBEROS
,
1899 SMB_SIGNING_DEFAULT
);
1901 if (NT_STATUS_IS_ERR(nt_status
)) {
1902 d_fprintf(stderr
, _("Unable to open a connection to %s to "
1903 "obtain data for %s\n"),
1904 servername
, printername
);
1906 talloc_destroy(mem_ctx
);
1910 /* Publish on AD server */
1912 ads_find_machine_acct(ads
, &res
, servername
);
1914 if (ads_count_replies(ads
, res
) == 0) {
1915 d_fprintf(stderr
, _("Could not find machine account for server "
1919 talloc_destroy(mem_ctx
);
1923 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1924 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1926 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1927 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1928 if (!srv_cn_escaped
|| !printername_escaped
) {
1929 SAFE_FREE(srv_cn_escaped
);
1930 SAFE_FREE(printername_escaped
);
1931 d_fprintf(stderr
, _("Internal error, out of memory!"));
1933 talloc_destroy(mem_ctx
);
1937 if (asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
) == -1) {
1938 SAFE_FREE(srv_cn_escaped
);
1939 SAFE_FREE(printername_escaped
);
1940 d_fprintf(stderr
, _("Internal error, out of memory!"));
1942 talloc_destroy(mem_ctx
);
1946 SAFE_FREE(srv_cn_escaped
);
1947 SAFE_FREE(printername_escaped
);
1949 nt_status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_spoolss
.syntax_id
, &pipe_hnd
);
1950 if (!NT_STATUS_IS_OK(nt_status
)) {
1951 d_fprintf(stderr
, _("Unable to open a connection to the spoolss pipe on %s\n"),
1955 talloc_destroy(mem_ctx
);
1959 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1963 talloc_destroy(mem_ctx
);
1967 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1968 if (!ADS_ERR_OK(rc
)) {
1969 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1972 talloc_destroy(mem_ctx
);
1976 d_printf("published printer\n");
1979 talloc_destroy(mem_ctx
);
1984 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1988 const char *servername
;
1990 LDAPMessage
*res
= NULL
;
1992 if (argc
< 1 || c
->display_usage
) {
1995 _("net ads printer remove <printername> [servername]\n"
1996 " Remove a printer from the AD\n"
1997 " printername\tName of the printer\n"
1998 " servername\tName of the print server\n"));
2002 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2007 servername
= argv
[1];
2009 servername
= lp_netbios_name();
2012 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
2014 if (!ADS_ERR_OK(rc
)) {
2015 d_fprintf(stderr
, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc
));
2016 ads_msgfree(ads
, res
);
2021 if (ads_count_replies(ads
, res
) == 0) {
2022 d_fprintf(stderr
, _("Printer '%s' not found\n"), argv
[1]);
2023 ads_msgfree(ads
, res
);
2028 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
2029 ads_msgfree(ads
, res
);
2030 rc
= ads_del_dn(ads
, prt_dn
);
2031 TALLOC_FREE(prt_dn
);
2033 if (!ADS_ERR_OK(rc
)) {
2034 d_fprintf(stderr
, _("ads_del_dn: %s\n"), ads_errstr(rc
));
2043 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
2045 struct functable func
[] = {
2048 net_ads_printer_search
,
2050 N_("Search for a printer"),
2051 N_("net ads printer search\n"
2052 " Search for a printer")
2056 net_ads_printer_info
,
2058 N_("Display printer information"),
2059 N_("net ads printer info\n"
2060 " Display printer information")
2064 net_ads_printer_publish
,
2066 N_("Publish a printer"),
2067 N_("net ads printer publish\n"
2068 " Publish a printer")
2072 net_ads_printer_remove
,
2074 N_("Delete a printer"),
2075 N_("net ads printer remove\n"
2076 " Delete a printer")
2078 {NULL
, NULL
, 0, NULL
, NULL
}
2081 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
2085 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
2088 const char *auth_principal
= c
->opt_user_name
;
2089 const char *auth_password
= c
->opt_password
;
2090 const char *realm
= NULL
;
2091 const char *new_password
= NULL
;
2096 if (c
->display_usage
) {
2099 _("net ads password <username>\n"
2100 " Change password for user\n"
2101 " username\tName of user to change password for\n"));
2105 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
2106 d_fprintf(stderr
, _("You must supply an administrator "
2107 "username/password\n"));
2112 d_fprintf(stderr
, _("ERROR: You must say which username to "
2113 "change password for\n"));
2118 if (!strchr_m(user
, '@')) {
2119 if (asprintf(&chr
, "%s@%s", argv
[0], lp_realm()) == -1) {
2125 use_in_memory_ccache();
2126 chr
= strchr_m(auth_principal
, '@');
2133 /* use the realm so we can eventually change passwords for users
2134 in realms other than default */
2135 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
2139 /* we don't actually need a full connect, but it's the easy way to
2140 fill in the KDC's addresss */
2143 if (!ads
->config
.realm
) {
2144 d_fprintf(stderr
, _("Didn't find the kerberos server!\n"));
2150 new_password
= (const char *)argv
[1];
2152 if (asprintf(&prompt
, _("Enter new password for %s:"), user
) == -1) {
2155 new_password
= getpass(prompt
);
2159 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
2160 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
2161 if (!ADS_ERR_OK(ret
)) {
2162 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2167 d_printf(_("Password change for %s completed.\n"), user
);
2173 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2176 char *host_principal
;
2180 if (c
->display_usage
) {
2182 "net ads changetrustpw\n"
2185 _("Change the machine account's trust password"));
2189 if (!secrets_init()) {
2190 DEBUG(1,("Failed to initialise secrets database\n"));
2194 net_use_krb_machine_account(c
);
2196 use_in_memory_ccache();
2198 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2202 fstrcpy(my_name
, lp_netbios_name());
2203 if (!strlower_m(my_name
)) {
2208 if (asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
) == -1) {
2212 d_printf(_("Changing password for principal: %s\n"), host_principal
);
2214 ret
= ads_change_trust_account_password(ads
, host_principal
);
2216 if (!ADS_ERR_OK(ret
)) {
2217 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2219 SAFE_FREE(host_principal
);
2223 d_printf(_("Password change for principal %s succeeded.\n"), host_principal
);
2225 if (USE_SYSTEM_KEYTAB
) {
2226 d_printf(_("Attempting to update system keytab with new password.\n"));
2227 if (ads_keytab_create_default(ads
)) {
2228 d_printf(_("Failed to update system keytab.\n"));
2233 SAFE_FREE(host_principal
);
2239 help for net ads search
2241 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
2244 "\nnet ads search <expression> <attributes...>\n"
2245 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2246 "The expression is a standard LDAP search expression, and the\n"
2247 "attributes are a list of LDAP fields to show in the results.\n\n"
2248 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2250 net_common_flags_usage(c
, argc
, argv
);
2256 general ADS search function. Useful in diagnosing problems in ADS
2258 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
2262 const char *ldap_exp
;
2264 LDAPMessage
*res
= NULL
;
2266 if (argc
< 1 || c
->display_usage
) {
2267 return net_ads_search_usage(c
, argc
, argv
);
2270 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2277 rc
= ads_do_search_retry(ads
, ads
->config
.bind_path
,
2279 ldap_exp
, attrs
, &res
);
2280 if (!ADS_ERR_OK(rc
)) {
2281 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2286 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2288 /* dump the results */
2291 ads_msgfree(ads
, res
);
2299 help for net ads search
2301 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
2304 "\nnet ads dn <dn> <attributes...>\n"
2305 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2306 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2307 "to show in the results\n\n"
2308 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2309 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2311 net_common_flags_usage(c
, argc
, argv
);
2317 general ADS search function. Useful in diagnosing problems in ADS
2319 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
2325 LDAPMessage
*res
= NULL
;
2327 if (argc
< 1 || c
->display_usage
) {
2328 return net_ads_dn_usage(c
, argc
, argv
);
2331 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2338 rc
= ads_do_search_all(ads
, dn
,
2340 "(objectclass=*)", attrs
, &res
);
2341 if (!ADS_ERR_OK(rc
)) {
2342 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2347 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2349 /* dump the results */
2352 ads_msgfree(ads
, res
);
2359 help for net ads sid search
2361 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2364 "\nnet ads sid <sid> <attributes...>\n"
2365 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2366 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2367 "to show in the results\n\n"
2368 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2370 net_common_flags_usage(c
, argc
, argv
);
2376 general ADS search function. Useful in diagnosing problems in ADS
2378 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2382 const char *sid_string
;
2384 LDAPMessage
*res
= NULL
;
2387 if (argc
< 1 || c
->display_usage
) {
2388 return net_ads_sid_usage(c
, argc
, argv
);
2391 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2395 sid_string
= argv
[0];
2398 if (!string_to_sid(&sid
, sid_string
)) {
2399 d_fprintf(stderr
, _("could not convert sid\n"));
2404 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2405 if (!ADS_ERR_OK(rc
)) {
2406 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2411 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2413 /* dump the results */
2416 ads_msgfree(ads
, res
);
2422 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2427 if (c
->display_usage
) {
2429 "net ads keytab flush\n"
2432 _("Delete the whole keytab"));
2436 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2439 ret
= ads_keytab_flush(ads
);
2444 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2450 if (c
->display_usage
) {
2453 _("net ads keytab add <principal> [principal ...]\n"
2454 " Add principals to local keytab\n"
2455 " principal\tKerberos principal to add to "
2460 d_printf(_("Processing principals to add...\n"));
2461 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2464 for (i
= 0; i
< argc
; i
++) {
2465 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2471 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2476 if (c
->display_usage
) {
2478 "net ads keytab create\n"
2481 _("Create new default keytab"));
2485 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2488 ret
= ads_keytab_create_default(ads
);
2493 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2495 const char *keytab
= NULL
;
2497 if (c
->display_usage
) {
2500 _("net ads keytab list [keytab]\n"
2501 " List a local keytab\n"
2502 " keytab\tKeytab to list\n"));
2510 return ads_keytab_list(keytab
);
2514 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2516 struct functable func
[] = {
2521 N_("Add a service principal"),
2522 N_("net ads keytab add\n"
2523 " Add a service principal")
2527 net_ads_keytab_create
,
2529 N_("Create a fresh keytab"),
2530 N_("net ads keytab create\n"
2531 " Create a fresh keytab")
2535 net_ads_keytab_flush
,
2537 N_("Remove all keytab entries"),
2538 N_("net ads keytab flush\n"
2539 " Remove all keytab entries")
2543 net_ads_keytab_list
,
2545 N_("List a keytab"),
2546 N_("net ads keytab list\n"
2549 {NULL
, NULL
, 0, NULL
, NULL
}
2552 if (!USE_KERBEROS_KEYTAB
) {
2553 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2554 "keytab method to use keytab functions.\n"));
2557 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2560 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2564 if (c
->display_usage
) {
2566 "net ads kerberos renew\n"
2569 _("Renew TGT from existing credential cache"));
2573 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2575 d_printf(_("failed to renew kerberos ticket: %s\n"),
2576 error_message(ret
));
2581 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2583 struct PAC_LOGON_INFO
*info
= NULL
;
2584 TALLOC_CTX
*mem_ctx
= NULL
;
2587 const char *impersonate_princ_s
= NULL
;
2589 if (c
->display_usage
) {
2591 "net ads kerberos pac\n"
2594 _("Dump the Kerberos PAC"));
2598 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2604 impersonate_princ_s
= argv
[0];
2607 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2609 status
= kerberos_return_pac(mem_ctx
,
2618 2592000, /* one month */
2619 impersonate_princ_s
,
2621 if (!NT_STATUS_IS_OK(status
)) {
2622 d_printf(_("failed to query kerberos PAC: %s\n"),
2629 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2630 d_printf(_("The Pac: %s\n"), s
);
2635 TALLOC_FREE(mem_ctx
);
2639 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2641 TALLOC_CTX
*mem_ctx
= NULL
;
2645 if (c
->display_usage
) {
2647 "net ads kerberos kinit\n"
2650 _("Get Ticket Granting Ticket (TGT) for the user"));
2654 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2659 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2661 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2669 2592000, /* one month */
2672 d_printf(_("failed to kinit password: %s\n"),
2679 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2681 struct functable func
[] = {
2684 net_ads_kerberos_kinit
,
2686 N_("Retrieve Ticket Granting Ticket (TGT)"),
2687 N_("net ads kerberos kinit\n"
2688 " Receive Ticket Granting Ticket (TGT)")
2692 net_ads_kerberos_renew
,
2694 N_("Renew Ticket Granting Ticket from credential cache"),
2695 N_("net ads kerberos renew\n"
2696 " Renew Ticket Granting Ticket (TGT) from "
2701 net_ads_kerberos_pac
,
2703 N_("Dump Kerberos PAC"),
2704 N_("net ads kerberos pac\n"
2705 " Dump Kerberos PAC")
2707 {NULL
, NULL
, 0, NULL
, NULL
}
2710 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2713 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2715 struct functable func
[] = {
2720 N_("Display details on remote ADS server"),
2722 " Display details on remote ADS server")
2728 N_("Join the local machine to ADS realm"),
2730 " Join the local machine to ADS realm")
2736 N_("Validate machine account"),
2737 N_("net ads testjoin\n"
2738 " Validate machine account")
2744 N_("Remove the local machine from ADS"),
2745 N_("net ads leave\n"
2746 " Remove the local machine from ADS")
2752 N_("Display machine account details"),
2753 N_("net ads status\n"
2754 " Display machine account details")
2760 N_("List/modify users"),
2762 " List/modify users")
2768 N_("List/modify groups"),
2769 N_("net ads group\n"
2770 " List/modify groups")
2776 N_("Issue dynamic DNS update"),
2778 " Issue dynamic DNS update")
2784 N_("Change user passwords"),
2785 N_("net ads password\n"
2786 " Change user passwords")
2790 net_ads_changetrustpw
,
2792 N_("Change trust account password"),
2793 N_("net ads changetrustpw\n"
2794 " Change trust account password")
2800 N_("List/modify printer entries"),
2801 N_("net ads printer\n"
2802 " List/modify printer entries")
2808 N_("Issue LDAP search using filter"),
2809 N_("net ads search\n"
2810 " Issue LDAP search using filter")
2816 N_("Issue LDAP search by DN"),
2818 " Issue LDAP search by DN")
2824 N_("Issue LDAP search by SID"),
2826 " Issue LDAP search by SID")
2832 N_("Display workgroup name"),
2833 N_("net ads workgroup\n"
2834 " Display the workgroup name")
2840 N_("Perfom CLDAP query on DC"),
2841 N_("net ads lookup\n"
2842 " Find the ADS DC using CLDAP lookups")
2848 N_("Manage local keytab file"),
2849 N_("net ads keytab\n"
2850 " Manage local keytab file")
2856 N_("Manage group policy objects"),
2858 " Manage group policy objects")
2864 N_("Manage kerberos keytab"),
2865 N_("net ads kerberos\n"
2866 " Manage kerberos keytab")
2868 {NULL
, NULL
, 0, NULL
, NULL
}
2871 return net_run_function(c
, argc
, argv
, "net ads", func
);
2876 static int net_ads_noads(void)
2878 d_fprintf(stderr
, _("ADS support not compiled in\n"));
2882 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2884 return net_ads_noads();
2887 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2889 return net_ads_noads();
2892 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2894 return net_ads_noads();
2897 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2899 return net_ads_noads();
2902 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2904 return net_ads_noads();
2907 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2909 return net_ads_noads();
2912 int net_ads_gpo(struct net_context
*c
, int argc
, const char **argv
)
2914 return net_ads_noads();
2917 /* this one shouldn't display a message */
2918 int net_ads_check(struct net_context
*c
)
2923 int net_ads_check_our_domain(struct net_context
*c
)
2928 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2930 return net_ads_noads();
2933 #endif /* HAVE_ADS */