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 if (!strupper_m(ads
->auth
.realm
)) {
292 return ADS_ERROR(LDAP_NO_MEMORY
);
296 status
= ads_connect(ads
);
298 if (!ADS_ERR_OK(status
)) {
300 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
301 NT_STATUS_NO_LOGON_SERVERS
)) {
302 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
307 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
308 need_password
= true;
317 /* when contacting our own domain, make sure we use the closest DC.
318 * This is done by reconnecting to ADS because only the first call to
319 * ads_connect will give us our own sitename */
321 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
323 tried_closest_dc
= true; /* avoid loop */
325 if (!ads_closest_dc(ads
)) {
327 namecache_delete(ads
->server
.realm
, 0x1C);
328 namecache_delete(ads
->server
.workgroup
, 0x1C);
341 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
343 return ads_startup_int(c
, only_own_domain
, 0, ads
);
346 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
348 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
352 Check to see if connection can be made via ads.
353 ads_startup() stores the password in opt_password if it needs to so
354 that rpc or rap can use it without re-prompting.
356 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
361 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
365 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
367 status
= ads_connect(ads
);
368 if ( !ADS_ERR_OK(status
) ) {
376 int net_ads_check_our_domain(struct net_context
*c
)
378 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
381 int net_ads_check(struct net_context
*c
)
383 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
387 determine the netbios workgroup name for a domain
389 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
392 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
394 if (c
->display_usage
) {
396 "net ads workgroup\n"
399 _("Print the workgroup name"));
403 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
404 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
408 if (!ads
->config
.realm
) {
409 ads
->config
.realm
= discard_const_p(char, c
->opt_target_workgroup
);
410 ads
->ldap
.port
= 389;
413 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads
->ldap
.ss
, ads
->server
.realm
, &reply
) ) {
414 d_fprintf(stderr
, _("CLDAP query failed!\n"));
419 d_printf(_("Workgroup: %s\n"), reply
.domain_name
);
428 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
430 char **disp_fields
= (char **) data_area
;
432 if (!field
) { /* must be end of record */
433 if (disp_fields
[0]) {
434 if (!strchr_m(disp_fields
[0], '$')) {
436 d_printf("%-21.21s %s\n",
437 disp_fields
[0], disp_fields
[1]);
439 d_printf("%s\n", disp_fields
[0]);
442 SAFE_FREE(disp_fields
[0]);
443 SAFE_FREE(disp_fields
[1]);
446 if (!values
) /* must be new field, indicate string field */
448 if (strcasecmp_m(field
, "sAMAccountName") == 0) {
449 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
451 if (strcasecmp_m(field
, "description") == 0)
452 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
456 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
458 return net_user_usage(c
, argc
, argv
);
461 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
466 LDAPMessage
*res
=NULL
;
470 if (argc
< 1 || c
->display_usage
)
471 return net_ads_user_usage(c
, argc
, argv
);
473 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
477 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
479 if (!ADS_ERR_OK(status
)) {
480 d_fprintf(stderr
, _("ads_user_add: %s\n"), ads_errstr(status
));
484 if (ads_count_replies(ads
, res
)) {
485 d_fprintf(stderr
, _("ads_user_add: User %s already exists\n"),
490 if (c
->opt_container
) {
491 ou_str
= SMB_STRDUP(c
->opt_container
);
493 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
496 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
498 if (!ADS_ERR_OK(status
)) {
499 d_fprintf(stderr
, _("Could not add user %s: %s\n"), argv
[0],
504 /* if no password is to be set, we're done */
506 d_printf(_("User %s added\n"), argv
[0]);
511 /* try setting the password */
512 if (asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
) == -1) {
515 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
516 ads
->auth
.time_offset
);
518 if (ADS_ERR_OK(status
)) {
519 d_printf(_("User %s added\n"), argv
[0]);
524 /* password didn't set, delete account */
525 d_fprintf(stderr
, _("Could not add user %s. "
526 "Error setting password %s\n"),
527 argv
[0], ads_errstr(status
));
528 ads_msgfree(ads
, res
);
529 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
530 if (ADS_ERR_OK(status
)) {
531 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
532 ads_del_dn(ads
, userdn
);
538 ads_msgfree(ads
, res
);
544 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
546 ADS_STRUCT
*ads
= NULL
;
548 LDAPMessage
*res
= NULL
;
552 const char *attrs
[] = {"memberOf", "primaryGroupID", NULL
};
553 char *searchstring
=NULL
;
557 struct dom_sid primary_group_sid
;
559 enum wbcSidType type
;
561 if (argc
< 1 || c
->display_usage
) {
562 return net_ads_user_usage(c
, argc
, argv
);
565 frame
= talloc_new(talloc_tos());
570 escaped_user
= escape_ldap_string(frame
, argv
[0]);
573 _("ads_user_info: failed to escape user %s\n"),
578 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
583 if (asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
) == -1) {
587 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
588 SAFE_FREE(searchstring
);
590 if (!ADS_ERR_OK(rc
)) {
591 d_fprintf(stderr
, _("ads_search: %s\n"), ads_errstr(rc
));
596 if (!ads_pull_uint32(ads
, res
, "primaryGroupID", &group_rid
)) {
597 d_fprintf(stderr
, _("ads_pull_uint32 failed\n"));
602 rc
= ads_domain_sid(ads
, &primary_group_sid
);
603 if (!ADS_ERR_OK(rc
)) {
604 d_fprintf(stderr
, _("ads_domain_sid: %s\n"), ads_errstr(rc
));
609 sid_append_rid(&primary_group_sid
, group_rid
);
611 wbc_status
= wbcLookupSid((struct wbcDomainSid
*)&primary_group_sid
,
612 NULL
, /* don't look up domain */
615 if (!WBC_ERROR_IS_OK(wbc_status
)) {
616 d_fprintf(stderr
, "wbcLookupSid: %s\n",
617 wbcErrorString(wbc_status
));
622 d_printf("%s\n", primary_group
);
624 wbcFreeMemory(primary_group
);
626 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
627 (LDAPMessage
*)res
, "memberOf");
632 for (i
=0;grouplist
[i
];i
++) {
633 groupname
= ldap_explode_dn(grouplist
[i
], 1);
634 d_printf("%s\n", groupname
[0]);
635 ldap_value_free(groupname
);
637 ldap_value_free(grouplist
);
641 if (res
) ads_msgfree(ads
, res
);
642 if (ads
) ads_destroy(&ads
);
647 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
651 LDAPMessage
*res
= NULL
;
655 return net_ads_user_usage(c
, argc
, argv
);
658 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
662 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
663 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
664 d_printf(_("User %s does not exist.\n"), argv
[0]);
665 ads_msgfree(ads
, res
);
669 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
670 ads_msgfree(ads
, res
);
671 rc
= ads_del_dn(ads
, userdn
);
673 if (ADS_ERR_OK(rc
)) {
674 d_printf(_("User %s deleted\n"), argv
[0]);
678 d_fprintf(stderr
, _("Error deleting user %s: %s\n"), argv
[0],
684 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
686 struct functable func
[] = {
691 N_("Add an AD user"),
692 N_("net ads user add\n"
699 N_("Display information about an AD user"),
700 N_("net ads user info\n"
701 " Display information about an AD user")
707 N_("Delete an AD user"),
708 N_("net ads user delete\n"
709 " Delete an AD user")
711 {NULL
, NULL
, 0, NULL
, NULL
}
715 const char *shortattrs
[] = {"sAMAccountName", NULL
};
716 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
717 char *disp_fields
[2] = {NULL
, NULL
};
720 if (c
->display_usage
) {
726 net_display_usage_from_functable(func
);
730 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
734 if (c
->opt_long_list_entries
)
735 d_printf(_("\nUser name Comment"
736 "\n-----------------------------\n"));
738 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
740 "(objectCategory=user)",
741 c
->opt_long_list_entries
? longattrs
:
742 shortattrs
, usergrp_display
,
745 return ADS_ERR_OK(rc
) ? 0 : -1;
748 return net_run_function(c
, argc
, argv
, "net ads user", func
);
751 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
753 return net_group_usage(c
, argc
, argv
);
756 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
760 LDAPMessage
*res
=NULL
;
764 if (argc
< 1 || c
->display_usage
) {
765 return net_ads_group_usage(c
, argc
, argv
);
768 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
772 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
774 if (!ADS_ERR_OK(status
)) {
775 d_fprintf(stderr
, _("ads_group_add: %s\n"), ads_errstr(status
));
779 if (ads_count_replies(ads
, res
)) {
780 d_fprintf(stderr
, _("ads_group_add: Group %s already exists\n"), argv
[0]);
784 if (c
->opt_container
) {
785 ou_str
= SMB_STRDUP(c
->opt_container
);
787 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
790 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
792 if (ADS_ERR_OK(status
)) {
793 d_printf(_("Group %s added\n"), argv
[0]);
796 d_fprintf(stderr
, _("Could not add group %s: %s\n"), argv
[0],
802 ads_msgfree(ads
, res
);
808 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
812 LDAPMessage
*res
= NULL
;
815 if (argc
< 1 || c
->display_usage
) {
816 return net_ads_group_usage(c
, argc
, argv
);
819 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
823 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
824 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
825 d_printf(_("Group %s does not exist.\n"), argv
[0]);
826 ads_msgfree(ads
, res
);
830 groupdn
= ads_get_dn(ads
, talloc_tos(), res
);
831 ads_msgfree(ads
, res
);
832 rc
= ads_del_dn(ads
, groupdn
);
833 TALLOC_FREE(groupdn
);
834 if (ADS_ERR_OK(rc
)) {
835 d_printf(_("Group %s deleted\n"), argv
[0]);
839 d_fprintf(stderr
, _("Error deleting group %s: %s\n"), argv
[0],
845 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
847 struct functable func
[] = {
852 N_("Add an AD group"),
853 N_("net ads group add\n"
860 N_("Delete an AD group"),
861 N_("net ads group delete\n"
862 " Delete an AD group")
864 {NULL
, NULL
, 0, NULL
, NULL
}
868 const char *shortattrs
[] = {"sAMAccountName", NULL
};
869 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
870 char *disp_fields
[2] = {NULL
, NULL
};
873 if (c
->display_usage
) {
878 _("List AD groups"));
879 net_display_usage_from_functable(func
);
883 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
887 if (c
->opt_long_list_entries
)
888 d_printf(_("\nGroup name Comment"
889 "\n-----------------------------\n"));
890 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
892 "(objectCategory=group)",
893 c
->opt_long_list_entries
? longattrs
:
894 shortattrs
, usergrp_display
,
898 return ADS_ERR_OK(rc
) ? 0 : -1;
900 return net_run_function(c
, argc
, argv
, "net ads group", func
);
903 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
909 if (c
->display_usage
) {
914 _("Display machine account details"));
918 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
922 rc
= ads_find_machine_acct(ads
, &res
, lp_netbios_name());
923 if (!ADS_ERR_OK(rc
)) {
924 d_fprintf(stderr
, _("ads_find_machine_acct: %s\n"), ads_errstr(rc
));
929 if (ads_count_replies(ads
, res
) == 0) {
930 d_fprintf(stderr
, _("No machine account for '%s' found\n"), lp_netbios_name());
940 /*******************************************************************
941 Leave an AD domain. Windows XP disables the machine account.
942 We'll try the same. The old code would do an LDAP delete.
943 That only worked using the machine creds because added the machine
944 with full control to the computer object's ACL.
945 *******************************************************************/
947 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
950 struct libnet_UnjoinCtx
*r
= NULL
;
953 if (c
->display_usage
) {
958 _("Leave an AD domain"));
963 d_fprintf(stderr
, _("No realm set, are we joined ?\n"));
967 if (!(ctx
= talloc_init("net_ads_leave"))) {
968 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
972 if (!c
->opt_kerberos
) {
973 use_in_memory_ccache();
977 d_fprintf(stderr
, _("Could not initialise message context. "
978 "Try running as root\n"));
982 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
983 if (!W_ERROR_IS_OK(werr
)) {
984 d_fprintf(stderr
, _("Could not initialise unjoin context.\n"));
989 r
->in
.use_kerberos
= c
->opt_kerberos
;
990 r
->in
.dc_name
= c
->opt_host
;
991 r
->in
.domain_name
= lp_realm();
992 r
->in
.admin_account
= c
->opt_user_name
;
993 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
994 r
->in
.modify_config
= lp_config_backend_is_registry();
996 /* Try to delete it, but if that fails, disable it. The
997 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
998 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
999 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
1000 r
->in
.delete_machine_account
= true;
1001 r
->in
.msg_ctx
= c
->msg_ctx
;
1003 werr
= libnet_Unjoin(ctx
, r
);
1004 if (!W_ERROR_IS_OK(werr
)) {
1005 d_printf(_("Failed to leave domain: %s\n"),
1006 r
->out
.error_string
? r
->out
.error_string
:
1007 get_friendly_werror_msg(werr
));
1011 if (r
->out
.deleted_machine_account
) {
1012 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1013 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1017 /* We couldn't delete it - see if the disable succeeded. */
1018 if (r
->out
.disabled_machine_account
) {
1019 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1020 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1025 /* Based on what we requested, we shouldn't get here, but if
1026 we did, it means the secrets were removed, and therefore
1027 we have left the domain */
1028 d_fprintf(stderr
, _("Machine '%s' Left domain '%s'\n"),
1029 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1035 if (W_ERROR_IS_OK(werr
)) {
1042 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
1044 ADS_STRUCT
*ads
= NULL
;
1047 struct sockaddr_storage dcip
;
1049 if (!secrets_init()) {
1050 DEBUG(1,("Failed to initialise secrets database\n"));
1051 return NT_STATUS_ACCESS_DENIED
;
1054 net_use_krb_machine_account(c
);
1056 get_dc_name(lp_workgroup(), lp_realm(), dc_name
, &dcip
);
1058 status
= ads_startup(c
, true, &ads
);
1059 if (!ADS_ERR_OK(status
)) {
1060 return ads_ntstatus(status
);
1064 return NT_STATUS_OK
;
1068 check that an existing join is OK
1070 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
1073 use_in_memory_ccache();
1075 if (c
->display_usage
) {
1077 "net ads testjoin\n"
1080 _("Test if the existing join is ok"));
1084 /* Display success or failure */
1085 status
= net_ads_join_ok(c
);
1086 if (!NT_STATUS_IS_OK(status
)) {
1087 fprintf(stderr
, _("Join to domain is not valid: %s\n"),
1088 get_friendly_nt_error_msg(status
));
1092 printf(_("Join is OK\n"));
1096 /*******************************************************************
1097 Simple configu checks before beginning the join
1098 ********************************************************************/
1100 static WERROR
check_ads_config( void )
1102 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
1103 d_printf(_("Host is not configured as a member server.\n"));
1104 return WERR_INVALID_DOMAIN_ROLE
;
1107 if (strlen(lp_netbios_name()) > 15) {
1108 d_printf(_("Our netbios name can be at most 15 chars long, "
1109 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1110 (unsigned int)strlen(lp_netbios_name()));
1111 return WERR_INVALID_COMPUTERNAME
;
1114 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1115 d_fprintf(stderr
, _("realm must be set in in %s for ADS "
1116 "join to succeed.\n"), get_dyn_CONFIGFILE());
1117 return WERR_INVALID_PARAM
;
1123 /*******************************************************************
1124 Send a DNS update request
1125 *******************************************************************/
1127 #if defined(WITH_DNS_UPDATES)
1128 #include "../lib/addns/dns.h"
1129 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
1130 const char *pszDomainName
, const char *pszHostName
,
1131 const struct sockaddr_storage
*sslist
,
1134 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1135 const char *machine_name
,
1136 const struct sockaddr_storage
*addrs
,
1139 struct dns_rr_ns
*nameservers
= NULL
;
1140 int ns_count
= 0, i
;
1141 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1144 const char *dns_hosts_file
;
1145 const char *dnsdomain
= NULL
;
1146 char *root_domain
= NULL
;
1148 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1149 d_printf(_("No DNS domain configured for %s. "
1150 "Unable to perform DNS Update.\n"), machine_name
);
1151 status
= NT_STATUS_INVALID_PARAMETER
;
1156 dns_hosts_file
= lp_parm_const_string(-1, "resolv", "host file", NULL
);
1157 status
= ads_dns_lookup_ns(ctx
, dns_hosts_file
,
1158 dnsdomain
, &nameservers
, &ns_count
);
1159 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1160 /* Child domains often do not have NS records. Look
1161 for the NS record for the forest root domain
1162 (rootDomainNamingContext in therootDSE) */
1164 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1165 LDAPMessage
*msg
= NULL
;
1167 ADS_STATUS ads_status
;
1169 if ( !ads
->ldap
.ld
) {
1170 ads_status
= ads_connect( ads
);
1171 if ( !ADS_ERR_OK(ads_status
) ) {
1172 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1177 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1178 "(objectclass=*)", rootname_attrs
, &msg
);
1179 if (!ADS_ERR_OK(ads_status
)) {
1183 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1185 ads_msgfree( ads
, msg
);
1189 root_domain
= ads_build_domain( root_dn
);
1192 ads_msgfree( ads
, msg
);
1194 /* try again for NS servers */
1196 status
= ads_dns_lookup_ns(ctx
, dns_hosts_file
, root_domain
,
1197 &nameservers
, &ns_count
);
1199 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1200 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1201 "realm\n", ads
->config
.realm
));
1205 dnsdomain
= root_domain
;
1209 for (i
=0; i
< ns_count
; i
++) {
1211 status
= NT_STATUS_UNSUCCESSFUL
;
1213 /* Now perform the dns update - we'll try non-secure and if we fail,
1214 we'll follow it up with a secure update */
1216 fstrcpy( dns_server
, nameservers
[i
].hostname
);
1218 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1219 if (ERR_DNS_IS_OK(dns_err
)) {
1220 status
= NT_STATUS_OK
;
1224 if (ERR_DNS_EQUAL(dns_err
, ERROR_DNS_INVALID_NAME_SERVER
) ||
1225 ERR_DNS_EQUAL(dns_err
, ERROR_DNS_CONNECTION_FAILED
) ||
1226 ERR_DNS_EQUAL(dns_err
, ERROR_DNS_SOCKET_ERROR
)) {
1227 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1228 dns_errstr(dns_err
)));
1232 d_printf(_("DNS Update for %s failed: %s\n"),
1233 machine_name
, dns_errstr(dns_err
));
1234 status
= NT_STATUS_UNSUCCESSFUL
;
1240 SAFE_FREE( root_domain
);
1245 static NTSTATUS
net_update_dns_ext(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
,
1246 const char *hostname
,
1247 struct sockaddr_storage
*iplist
,
1250 struct sockaddr_storage
*iplist_alloc
= NULL
;
1251 fstring machine_name
;
1255 fstrcpy(machine_name
, hostname
);
1257 name_to_fqdn( machine_name
, lp_netbios_name() );
1259 if (!strlower_m( machine_name
)) {
1260 return NT_STATUS_INVALID_PARAMETER
;
1263 if (num_addrs
== 0 || iplist
== NULL
) {
1265 * Get our ip address
1266 * (not the 127.0.0.x address but a real ip address)
1268 num_addrs
= get_my_ip_address(&iplist_alloc
);
1269 if ( num_addrs
<= 0 ) {
1270 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1271 "non-loopback IP addresses!\n"));
1272 return NT_STATUS_INVALID_PARAMETER
;
1274 iplist
= iplist_alloc
;
1277 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1280 SAFE_FREE(iplist_alloc
);
1284 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
, const char *hostname
)
1288 status
= net_update_dns_ext(mem_ctx
, ads
, hostname
, NULL
, 0);
1294 /*******************************************************************
1295 ********************************************************************/
1297 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1299 d_printf(_("net ads join [options]\n"
1300 "Valid options:\n"));
1301 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1302 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1303 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1304 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1305 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1306 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1307 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1308 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1309 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1310 " NB: osName and osVer must be specified together for either to take effect.\n"
1311 " Also, the operatingSystemService attribute is also set when along with\n"
1312 " the two other attributes.\n"));
1318 static void _net_ads_join_dns_updates(TALLOC_CTX
*ctx
, struct libnet_JoinCtx
*r
)
1320 #if defined(WITH_DNS_UPDATES)
1321 ADS_STRUCT
*ads_dns
= NULL
;
1326 * In a clustered environment, don't do dynamic dns updates:
1327 * Registering the set of ip addresses that are assigned to
1328 * the interfaces of the node that performs the join does usually
1329 * not have the desired effect, since the local interfaces do not
1330 * carry the complete set of the cluster's public IP addresses.
1331 * And it can also contain internal addresses that should not
1332 * be visible to the outside at all.
1333 * In order to do dns updates in a clustererd setup, use
1334 * net ads dns register.
1336 if (lp_clustering()) {
1337 d_fprintf(stderr
, _("Not doing automatic DNS update in a "
1338 "clustered setup.\n"));
1342 if (!r
->out
.domain_is_ad
) {
1347 * We enter this block with user creds.
1348 * kinit with the machine password to do dns update.
1351 ads_dns
= ads_init(lp_realm(), NULL
, r
->in
.dc_name
);
1353 if (ads_dns
== NULL
) {
1354 d_fprintf(stderr
, _("DNS update failed: out of memory!\n"));
1358 use_in_memory_ccache();
1360 ret
= asprintf(&ads_dns
->auth
.user_name
, "%s$", lp_netbios_name());
1362 d_fprintf(stderr
, _("DNS update failed: out of memory\n"));
1366 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1367 r
->out
.netbios_domain_name
, NULL
, NULL
);
1368 if (ads_dns
->auth
.password
== NULL
) {
1369 d_fprintf(stderr
, _("DNS update failed: out of memory\n"));
1373 ads_dns
->auth
.realm
= SMB_STRDUP(r
->out
.dns_domain_name
);
1374 if (ads_dns
->auth
.realm
== NULL
) {
1375 d_fprintf(stderr
, _("DNS update failed: out of memory\n"));
1379 if (!strupper_m(ads_dns
->auth
.realm
)) {
1380 d_fprintf(stderr
, _("strupper_m %s failed\n"), ads_dns
->auth
.realm
);
1384 ret
= ads_kinit_password(ads_dns
);
1387 _("DNS update failed: kinit failed: %s\n"),
1388 error_message(ret
));
1392 status
= net_update_dns(ctx
, ads_dns
, NULL
);
1393 if (!NT_STATUS_IS_OK(status
)) {
1394 d_fprintf( stderr
, _("DNS update failed: %s\n"),
1399 ads_destroy(&ads_dns
);
1406 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1408 TALLOC_CTX
*ctx
= NULL
;
1409 struct libnet_JoinCtx
*r
= NULL
;
1410 const char *domain
= lp_realm();
1411 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1412 bool createupn
= false;
1413 const char *machineupn
= NULL
;
1414 const char *create_in_ou
= NULL
;
1416 const char *os_name
= NULL
;
1417 const char *os_version
= NULL
;
1418 bool modify_config
= lp_config_backend_is_registry();
1420 if (c
->display_usage
)
1421 return net_ads_join_usage(c
, argc
, argv
);
1423 if (!modify_config
) {
1425 werr
= check_ads_config();
1426 if (!W_ERROR_IS_OK(werr
)) {
1427 d_fprintf(stderr
, _("Invalid configuration. Exiting....\n"));
1432 if (!(ctx
= talloc_init("net_ads_join"))) {
1433 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
1438 if (!c
->opt_kerberos
) {
1439 use_in_memory_ccache();
1442 werr
= libnet_init_JoinCtx(ctx
, &r
);
1443 if (!W_ERROR_IS_OK(werr
)) {
1447 /* process additional command line args */
1449 for ( i
=0; i
<argc
; i
++ ) {
1450 if ( !strncasecmp_m(argv
[i
], "createupn", strlen("createupn")) ) {
1452 machineupn
= get_string_param(argv
[i
]);
1454 else if ( !strncasecmp_m(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1455 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1456 d_fprintf(stderr
, _("Please supply a valid OU path.\n"));
1457 werr
= WERR_INVALID_PARAM
;
1461 else if ( !strncasecmp_m(argv
[i
], "osName", strlen("osName")) ) {
1462 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1463 d_fprintf(stderr
, _("Please supply a operating system name.\n"));
1464 werr
= WERR_INVALID_PARAM
;
1468 else if ( !strncasecmp_m(argv
[i
], "osVer", strlen("osVer")) ) {
1469 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1470 d_fprintf(stderr
, _("Please supply a valid operating system version.\n"));
1471 werr
= WERR_INVALID_PARAM
;
1481 d_fprintf(stderr
, _("Please supply a valid domain name\n"));
1482 werr
= WERR_INVALID_PARAM
;
1487 d_fprintf(stderr
, _("Could not initialise message context. "
1488 "Try running as root\n"));
1489 werr
= WERR_ACCESS_DENIED
;
1493 /* Do the domain join here */
1495 r
->in
.domain_name
= domain
;
1496 r
->in
.create_upn
= createupn
;
1497 r
->in
.upn
= machineupn
;
1498 r
->in
.account_ou
= create_in_ou
;
1499 r
->in
.os_name
= os_name
;
1500 r
->in
.os_version
= os_version
;
1501 r
->in
.dc_name
= c
->opt_host
;
1502 r
->in
.admin_account
= c
->opt_user_name
;
1503 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1505 r
->in
.use_kerberos
= c
->opt_kerberos
;
1506 r
->in
.modify_config
= modify_config
;
1507 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1508 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1509 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1510 r
->in
.msg_ctx
= c
->msg_ctx
;
1512 werr
= libnet_Join(ctx
, r
);
1513 if (W_ERROR_EQUAL(werr
, WERR_DCNOTFOUND
) &&
1514 strequal(domain
, lp_realm())) {
1515 r
->in
.domain_name
= lp_workgroup();
1516 werr
= libnet_Join(ctx
, r
);
1518 if (!W_ERROR_IS_OK(werr
)) {
1522 /* Check the short name of the domain */
1524 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1525 d_printf(_("The workgroup in %s does not match the short\n"
1526 "domain name obtained from the server.\n"
1527 "Using the name [%s] from the server.\n"
1528 "You should set \"workgroup = %s\" in %s.\n"),
1529 get_dyn_CONFIGFILE(), r
->out
.netbios_domain_name
,
1530 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1533 d_printf(_("Using short domain name -- %s\n"), r
->out
.netbios_domain_name
);
1535 if (r
->out
.dns_domain_name
) {
1536 d_printf(_("Joined '%s' to realm '%s'\n"), r
->in
.machine_name
,
1537 r
->out
.dns_domain_name
);
1539 d_printf(_("Joined '%s' to domain '%s'\n"), r
->in
.machine_name
,
1540 r
->out
.netbios_domain_name
);
1544 * We try doing the dns update (if it was compiled in).
1545 * If the dns update fails, we still consider the join
1546 * operation as succeeded if we came this far.
1548 _net_ads_join_dns_updates(ctx
, r
);
1556 /* issue an overall failure message at the end. */
1557 d_printf(_("Failed to join domain: %s\n"),
1558 r
&& r
->out
.error_string
? r
->out
.error_string
:
1559 get_friendly_werror_msg(werr
));
1565 /*******************************************************************
1566 ********************************************************************/
1568 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1570 #if defined(WITH_DNS_UPDATES)
1575 const char *hostname
= NULL
;
1576 const char **addrs_list
= NULL
;
1577 struct sockaddr_storage
*addrs
= NULL
;
1582 talloc_enable_leak_report();
1585 if (argc
<= 1 && lp_clustering() && lp_cluster_addresses() == NULL
) {
1586 d_fprintf(stderr
, _("Refusing DNS updates with automatic "
1587 "detection of addresses in a clustered "
1589 c
->display_usage
= true;
1592 if (c
->display_usage
) {
1594 "net ads dns register [hostname [IP [IP...]]]\n"
1597 _("Register hostname with DNS\n"));
1601 if (!(ctx
= talloc_init("net_ads_dns"))) {
1602 d_fprintf(stderr
, _("Could not initialise talloc context\n"));
1611 num_addrs
= argc
- 1;
1612 addrs_list
= &argv
[1];
1613 } else if (lp_clustering()) {
1614 addrs_list
= lp_cluster_addresses();
1615 num_addrs
= str_list_length(addrs_list
);
1618 if (num_addrs
> 0) {
1619 addrs
= talloc_zero_array(ctx
, struct sockaddr_storage
, num_addrs
);
1620 if (addrs
== NULL
) {
1621 d_fprintf(stderr
, _("Error allocating memory!\n"));
1627 for (count
= 0; count
< num_addrs
; count
++) {
1628 if (!interpret_string_addr(&addrs
[count
], addrs_list
[count
], 0)) {
1629 d_fprintf(stderr
, "%s '%s'.\n",
1630 _("Cannot interpret address"),
1637 status
= ads_startup(c
, true, &ads
);
1638 if ( !ADS_ERR_OK(status
) ) {
1639 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1644 ntstatus
= net_update_dns_ext(ctx
, ads
, hostname
, addrs
, num_addrs
);
1645 if (!NT_STATUS_IS_OK(ntstatus
)) {
1646 d_fprintf( stderr
, _("DNS update failed!\n") );
1647 ads_destroy( &ads
);
1652 d_fprintf( stderr
, _("Successfully registered hostname with DNS\n") );
1660 _("DNS update support not enabled at compile time!\n"));
1665 #if defined(WITH_DNS_UPDATES)
1666 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1669 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1671 #if defined(WITH_DNS_UPDATES)
1675 talloc_enable_leak_report();
1678 if (argc
!= 2 || c
->display_usage
) {
1683 _("net ads dns gethostbyname <server> <name>\n"),
1684 _(" Look up hostname from the AD\n"
1685 " server\tName server to use\n"
1686 " name\tName to look up\n"));
1690 err
= do_gethostbyname(argv
[0], argv
[1]);
1692 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1693 dns_errstr(err
), ERROR_DNS_V(err
));
1698 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1700 struct functable func
[] = {
1703 net_ads_dns_register
,
1705 N_("Add host dns entry to AD"),
1706 N_("net ads dns register\n"
1707 " Add host dns entry to AD")
1711 net_ads_dns_gethostbyname
,
1714 N_("net ads dns gethostbyname\n"
1717 {NULL
, NULL
, 0, NULL
, NULL
}
1720 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1723 /*******************************************************************
1724 ********************************************************************/
1726 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1729 "\nnet ads printer search <printer>"
1730 "\n\tsearch for a printer in the directory\n"
1731 "\nnet ads printer info <printer> <server>"
1732 "\n\tlookup info in directory for printer on server"
1733 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1734 "\nnet ads printer publish <printername>"
1735 "\n\tpublish printer in directory"
1736 "\n\t(note: printer name is required)\n"
1737 "\nnet ads printer remove <printername>"
1738 "\n\tremove printer from directory"
1739 "\n\t(note: printer name is required)\n"));
1743 /*******************************************************************
1744 ********************************************************************/
1746 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1750 LDAPMessage
*res
= NULL
;
1752 if (c
->display_usage
) {
1754 "net ads printer search\n"
1757 _("List printers in the AD"));
1761 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1765 rc
= ads_find_printers(ads
, &res
);
1767 if (!ADS_ERR_OK(rc
)) {
1768 d_fprintf(stderr
, _("ads_find_printer: %s\n"), ads_errstr(rc
));
1769 ads_msgfree(ads
, res
);
1774 if (ads_count_replies(ads
, res
) == 0) {
1775 d_fprintf(stderr
, _("No results found\n"));
1776 ads_msgfree(ads
, res
);
1782 ads_msgfree(ads
, res
);
1787 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1791 const char *servername
, *printername
;
1792 LDAPMessage
*res
= NULL
;
1794 if (c
->display_usage
) {
1797 _("net ads printer info [printername [servername]]\n"
1798 " Display printer info from AD\n"
1799 " printername\tPrinter name or wildcard\n"
1800 " servername\tName of the print server\n"));
1804 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1809 printername
= argv
[0];
1815 servername
= argv
[1];
1817 servername
= lp_netbios_name();
1820 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1822 if (!ADS_ERR_OK(rc
)) {
1823 d_fprintf(stderr
, _("Server '%s' not found: %s\n"),
1824 servername
, ads_errstr(rc
));
1825 ads_msgfree(ads
, res
);
1830 if (ads_count_replies(ads
, res
) == 0) {
1831 d_fprintf(stderr
, _("Printer '%s' not found\n"), printername
);
1832 ads_msgfree(ads
, res
);
1838 ads_msgfree(ads
, res
);
1844 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1848 const char *servername
, *printername
;
1849 struct cli_state
*cli
= NULL
;
1850 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1851 struct sockaddr_storage server_ss
;
1853 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1854 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1855 char *prt_dn
, *srv_dn
, **srv_cn
;
1856 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1857 LDAPMessage
*res
= NULL
;
1859 if (argc
< 1 || c
->display_usage
) {
1862 _("net ads printer publish <printername> [servername]\n"
1863 " Publish printer in AD\n"
1864 " printername\tName of the printer\n"
1865 " servername\tName of the print server\n"));
1866 talloc_destroy(mem_ctx
);
1870 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1871 talloc_destroy(mem_ctx
);
1875 printername
= argv
[0];
1878 servername
= argv
[1];
1880 servername
= lp_netbios_name();
1883 /* Get printer data from SPOOLSS */
1885 resolve_name(servername
, &server_ss
, 0x20, false);
1887 nt_status
= cli_full_connection(&cli
, lp_netbios_name(), servername
,
1890 c
->opt_user_name
, c
->opt_workgroup
,
1891 c
->opt_password
? c
->opt_password
: "",
1892 CLI_FULL_CONNECTION_USE_KERBEROS
,
1893 SMB_SIGNING_DEFAULT
);
1895 if (NT_STATUS_IS_ERR(nt_status
)) {
1896 d_fprintf(stderr
, _("Unable to open a connection to %s to "
1897 "obtain data for %s\n"),
1898 servername
, printername
);
1900 talloc_destroy(mem_ctx
);
1904 /* Publish on AD server */
1906 ads_find_machine_acct(ads
, &res
, servername
);
1908 if (ads_count_replies(ads
, res
) == 0) {
1909 d_fprintf(stderr
, _("Could not find machine account for server "
1913 talloc_destroy(mem_ctx
);
1917 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1918 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1920 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1921 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1922 if (!srv_cn_escaped
|| !printername_escaped
) {
1923 SAFE_FREE(srv_cn_escaped
);
1924 SAFE_FREE(printername_escaped
);
1925 d_fprintf(stderr
, _("Internal error, out of memory!"));
1927 talloc_destroy(mem_ctx
);
1931 if (asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
) == -1) {
1932 SAFE_FREE(srv_cn_escaped
);
1933 SAFE_FREE(printername_escaped
);
1934 d_fprintf(stderr
, _("Internal error, out of memory!"));
1936 talloc_destroy(mem_ctx
);
1940 SAFE_FREE(srv_cn_escaped
);
1941 SAFE_FREE(printername_escaped
);
1943 nt_status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_spoolss
.syntax_id
, &pipe_hnd
);
1944 if (!NT_STATUS_IS_OK(nt_status
)) {
1945 d_fprintf(stderr
, _("Unable to open a connection to the spoolss pipe on %s\n"),
1949 talloc_destroy(mem_ctx
);
1953 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1957 talloc_destroy(mem_ctx
);
1961 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1962 if (!ADS_ERR_OK(rc
)) {
1963 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1966 talloc_destroy(mem_ctx
);
1970 d_printf("published printer\n");
1973 talloc_destroy(mem_ctx
);
1978 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1982 const char *servername
;
1984 LDAPMessage
*res
= NULL
;
1986 if (argc
< 1 || c
->display_usage
) {
1989 _("net ads printer remove <printername> [servername]\n"
1990 " Remove a printer from the AD\n"
1991 " printername\tName of the printer\n"
1992 " servername\tName of the print server\n"));
1996 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2001 servername
= argv
[1];
2003 servername
= lp_netbios_name();
2006 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
2008 if (!ADS_ERR_OK(rc
)) {
2009 d_fprintf(stderr
, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc
));
2010 ads_msgfree(ads
, res
);
2015 if (ads_count_replies(ads
, res
) == 0) {
2016 d_fprintf(stderr
, _("Printer '%s' not found\n"), argv
[1]);
2017 ads_msgfree(ads
, res
);
2022 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
2023 ads_msgfree(ads
, res
);
2024 rc
= ads_del_dn(ads
, prt_dn
);
2025 TALLOC_FREE(prt_dn
);
2027 if (!ADS_ERR_OK(rc
)) {
2028 d_fprintf(stderr
, _("ads_del_dn: %s\n"), ads_errstr(rc
));
2037 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
2039 struct functable func
[] = {
2042 net_ads_printer_search
,
2044 N_("Search for a printer"),
2045 N_("net ads printer search\n"
2046 " Search for a printer")
2050 net_ads_printer_info
,
2052 N_("Display printer information"),
2053 N_("net ads printer info\n"
2054 " Display printer information")
2058 net_ads_printer_publish
,
2060 N_("Publish a printer"),
2061 N_("net ads printer publish\n"
2062 " Publish a printer")
2066 net_ads_printer_remove
,
2068 N_("Delete a printer"),
2069 N_("net ads printer remove\n"
2070 " Delete a printer")
2072 {NULL
, NULL
, 0, NULL
, NULL
}
2075 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
2079 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
2082 const char *auth_principal
= c
->opt_user_name
;
2083 const char *auth_password
= c
->opt_password
;
2084 const char *realm
= NULL
;
2085 const char *new_password
= NULL
;
2090 if (c
->display_usage
) {
2093 _("net ads password <username>\n"
2094 " Change password for user\n"
2095 " username\tName of user to change password for\n"));
2099 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
2100 d_fprintf(stderr
, _("You must supply an administrator "
2101 "username/password\n"));
2106 d_fprintf(stderr
, _("ERROR: You must say which username to "
2107 "change password for\n"));
2112 if (!strchr_m(user
, '@')) {
2113 if (asprintf(&chr
, "%s@%s", argv
[0], lp_realm()) == -1) {
2119 use_in_memory_ccache();
2120 chr
= strchr_m(auth_principal
, '@');
2127 /* use the realm so we can eventually change passwords for users
2128 in realms other than default */
2129 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
2133 /* we don't actually need a full connect, but it's the easy way to
2134 fill in the KDC's addresss */
2137 if (!ads
->config
.realm
) {
2138 d_fprintf(stderr
, _("Didn't find the kerberos server!\n"));
2144 new_password
= (const char *)argv
[1];
2146 if (asprintf(&prompt
, _("Enter new password for %s:"), user
) == -1) {
2149 new_password
= getpass(prompt
);
2153 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
2154 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
2155 if (!ADS_ERR_OK(ret
)) {
2156 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2161 d_printf(_("Password change for %s completed.\n"), user
);
2167 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2170 char *host_principal
;
2174 if (c
->display_usage
) {
2176 "net ads changetrustpw\n"
2179 _("Change the machine account's trust password"));
2183 if (!secrets_init()) {
2184 DEBUG(1,("Failed to initialise secrets database\n"));
2188 net_use_krb_machine_account(c
);
2190 use_in_memory_ccache();
2192 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2196 fstrcpy(my_name
, lp_netbios_name());
2197 if (!strlower_m(my_name
)) {
2202 if (asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
) == -1) {
2206 d_printf(_("Changing password for principal: %s\n"), host_principal
);
2208 ret
= ads_change_trust_account_password(ads
, host_principal
);
2210 if (!ADS_ERR_OK(ret
)) {
2211 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2213 SAFE_FREE(host_principal
);
2217 d_printf(_("Password change for principal %s succeeded.\n"), host_principal
);
2219 if (USE_SYSTEM_KEYTAB
) {
2220 d_printf(_("Attempting to update system keytab with new password.\n"));
2221 if (ads_keytab_create_default(ads
)) {
2222 d_printf(_("Failed to update system keytab.\n"));
2227 SAFE_FREE(host_principal
);
2233 help for net ads search
2235 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
2238 "\nnet ads search <expression> <attributes...>\n"
2239 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2240 "The expression is a standard LDAP search expression, and the\n"
2241 "attributes are a list of LDAP fields to show in the results.\n\n"
2242 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2244 net_common_flags_usage(c
, argc
, argv
);
2250 general ADS search function. Useful in diagnosing problems in ADS
2252 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
2256 const char *ldap_exp
;
2258 LDAPMessage
*res
= NULL
;
2260 if (argc
< 1 || c
->display_usage
) {
2261 return net_ads_search_usage(c
, argc
, argv
);
2264 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2271 rc
= ads_do_search_retry(ads
, ads
->config
.bind_path
,
2273 ldap_exp
, attrs
, &res
);
2274 if (!ADS_ERR_OK(rc
)) {
2275 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2280 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2282 /* dump the results */
2285 ads_msgfree(ads
, res
);
2293 help for net ads search
2295 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
2298 "\nnet ads dn <dn> <attributes...>\n"
2299 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2300 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2301 "to show in the results\n\n"
2302 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2303 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2305 net_common_flags_usage(c
, argc
, argv
);
2311 general ADS search function. Useful in diagnosing problems in ADS
2313 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
2319 LDAPMessage
*res
= NULL
;
2321 if (argc
< 1 || c
->display_usage
) {
2322 return net_ads_dn_usage(c
, argc
, argv
);
2325 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2332 rc
= ads_do_search_all(ads
, dn
,
2334 "(objectclass=*)", attrs
, &res
);
2335 if (!ADS_ERR_OK(rc
)) {
2336 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2341 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2343 /* dump the results */
2346 ads_msgfree(ads
, res
);
2353 help for net ads sid search
2355 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2358 "\nnet ads sid <sid> <attributes...>\n"
2359 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2360 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2361 "to show in the results\n\n"
2362 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2364 net_common_flags_usage(c
, argc
, argv
);
2370 general ADS search function. Useful in diagnosing problems in ADS
2372 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2376 const char *sid_string
;
2378 LDAPMessage
*res
= NULL
;
2381 if (argc
< 1 || c
->display_usage
) {
2382 return net_ads_sid_usage(c
, argc
, argv
);
2385 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2389 sid_string
= argv
[0];
2392 if (!string_to_sid(&sid
, sid_string
)) {
2393 d_fprintf(stderr
, _("could not convert sid\n"));
2398 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2399 if (!ADS_ERR_OK(rc
)) {
2400 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2405 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2407 /* dump the results */
2410 ads_msgfree(ads
, res
);
2416 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2421 if (c
->display_usage
) {
2423 "net ads keytab flush\n"
2426 _("Delete the whole keytab"));
2430 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2433 ret
= ads_keytab_flush(ads
);
2438 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2444 if (c
->display_usage
) {
2447 _("net ads keytab add <principal> [principal ...]\n"
2448 " Add principals to local keytab\n"
2449 " principal\tKerberos principal to add to "
2454 d_printf(_("Processing principals to add...\n"));
2455 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2458 for (i
= 0; i
< argc
; i
++) {
2459 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2465 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2470 if (c
->display_usage
) {
2472 "net ads keytab create\n"
2475 _("Create new default keytab"));
2479 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2482 ret
= ads_keytab_create_default(ads
);
2487 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2489 const char *keytab
= NULL
;
2491 if (c
->display_usage
) {
2494 _("net ads keytab list [keytab]\n"
2495 " List a local keytab\n"
2496 " keytab\tKeytab to list\n"));
2504 return ads_keytab_list(keytab
);
2508 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2510 struct functable func
[] = {
2515 N_("Add a service principal"),
2516 N_("net ads keytab add\n"
2517 " Add a service principal")
2521 net_ads_keytab_create
,
2523 N_("Create a fresh keytab"),
2524 N_("net ads keytab create\n"
2525 " Create a fresh keytab")
2529 net_ads_keytab_flush
,
2531 N_("Remove all keytab entries"),
2532 N_("net ads keytab flush\n"
2533 " Remove all keytab entries")
2537 net_ads_keytab_list
,
2539 N_("List a keytab"),
2540 N_("net ads keytab list\n"
2543 {NULL
, NULL
, 0, NULL
, NULL
}
2546 if (!USE_KERBEROS_KEYTAB
) {
2547 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2548 "keytab method to use keytab functions.\n"));
2551 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2554 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2558 if (c
->display_usage
) {
2560 "net ads kerberos renew\n"
2563 _("Renew TGT from existing credential cache"));
2567 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2569 d_printf(_("failed to renew kerberos ticket: %s\n"),
2570 error_message(ret
));
2575 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2577 struct PAC_LOGON_INFO
*info
= NULL
;
2578 TALLOC_CTX
*mem_ctx
= NULL
;
2581 const char *impersonate_princ_s
= NULL
;
2583 if (c
->display_usage
) {
2585 "net ads kerberos pac\n"
2588 _("Dump the Kerberos PAC"));
2592 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2598 impersonate_princ_s
= argv
[0];
2601 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2603 status
= kerberos_return_pac(mem_ctx
,
2612 2592000, /* one month */
2613 impersonate_princ_s
,
2615 if (!NT_STATUS_IS_OK(status
)) {
2616 d_printf(_("failed to query kerberos PAC: %s\n"),
2623 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2624 d_printf(_("The Pac: %s\n"), s
);
2629 TALLOC_FREE(mem_ctx
);
2633 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2635 TALLOC_CTX
*mem_ctx
= NULL
;
2639 if (c
->display_usage
) {
2641 "net ads kerberos kinit\n"
2644 _("Get Ticket Granting Ticket (TGT) for the user"));
2648 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2653 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2655 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2663 2592000, /* one month */
2666 d_printf(_("failed to kinit password: %s\n"),
2673 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2675 struct functable func
[] = {
2678 net_ads_kerberos_kinit
,
2680 N_("Retrieve Ticket Granting Ticket (TGT)"),
2681 N_("net ads kerberos kinit\n"
2682 " Receive Ticket Granting Ticket (TGT)")
2686 net_ads_kerberos_renew
,
2688 N_("Renew Ticket Granting Ticket from credential cache"),
2689 N_("net ads kerberos renew\n"
2690 " Renew Ticket Granting Ticket (TGT) from "
2695 net_ads_kerberos_pac
,
2697 N_("Dump Kerberos PAC"),
2698 N_("net ads kerberos pac\n"
2699 " Dump Kerberos PAC")
2701 {NULL
, NULL
, 0, NULL
, NULL
}
2704 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2707 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2709 struct functable func
[] = {
2714 N_("Display details on remote ADS server"),
2716 " Display details on remote ADS server")
2722 N_("Join the local machine to ADS realm"),
2724 " Join the local machine to ADS realm")
2730 N_("Validate machine account"),
2731 N_("net ads testjoin\n"
2732 " Validate machine account")
2738 N_("Remove the local machine from ADS"),
2739 N_("net ads leave\n"
2740 " Remove the local machine from ADS")
2746 N_("Display machine account details"),
2747 N_("net ads status\n"
2748 " Display machine account details")
2754 N_("List/modify users"),
2756 " List/modify users")
2762 N_("List/modify groups"),
2763 N_("net ads group\n"
2764 " List/modify groups")
2770 N_("Issue dynamic DNS update"),
2772 " Issue dynamic DNS update")
2778 N_("Change user passwords"),
2779 N_("net ads password\n"
2780 " Change user passwords")
2784 net_ads_changetrustpw
,
2786 N_("Change trust account password"),
2787 N_("net ads changetrustpw\n"
2788 " Change trust account password")
2794 N_("List/modify printer entries"),
2795 N_("net ads printer\n"
2796 " List/modify printer entries")
2802 N_("Issue LDAP search using filter"),
2803 N_("net ads search\n"
2804 " Issue LDAP search using filter")
2810 N_("Issue LDAP search by DN"),
2812 " Issue LDAP search by DN")
2818 N_("Issue LDAP search by SID"),
2820 " Issue LDAP search by SID")
2826 N_("Display workgroup name"),
2827 N_("net ads workgroup\n"
2828 " Display the workgroup name")
2834 N_("Perfom CLDAP query on DC"),
2835 N_("net ads lookup\n"
2836 " Find the ADS DC using CLDAP lookups")
2842 N_("Manage local keytab file"),
2843 N_("net ads keytab\n"
2844 " Manage local keytab file")
2850 N_("Manage group policy objects"),
2852 " Manage group policy objects")
2858 N_("Manage kerberos keytab"),
2859 N_("net ads kerberos\n"
2860 " Manage kerberos keytab")
2862 {NULL
, NULL
, 0, NULL
, NULL
}
2865 return net_run_function(c
, argc
, argv
, "net ads", func
);
2870 static int net_ads_noads(void)
2872 d_fprintf(stderr
, _("ADS support not compiled in\n"));
2876 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2878 return net_ads_noads();
2881 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2883 return net_ads_noads();
2886 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2888 return net_ads_noads();
2891 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2893 return net_ads_noads();
2896 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2898 return net_ads_noads();
2901 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2903 return net_ads_noads();
2906 int net_ads_gpo(struct net_context
*c
, int argc
, const char **argv
)
2908 return net_ads_noads();
2911 /* this one shouldn't display a message */
2912 int net_ads_check(struct net_context
*c
)
2917 int net_ads_check_our_domain(struct net_context
*c
)
2922 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2924 return net_ads_noads();
2927 #endif /* HAVE_ADS */