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 "libads/dns.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 "utils/net_dns.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
);
65 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
66 d_fprintf(stderr
, _("CLDAP query failed!\n"));
70 d_printf(_("Information for Domain Controller: %s\n\n"),
73 d_printf(_("Response Type: "));
74 switch (reply
.command
) {
75 case LOGON_SAM_LOGON_USER_UNKNOWN_EX
:
76 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
78 case LOGON_SAM_LOGON_RESPONSE_EX
:
79 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
82 d_printf("0x%x\n", reply
.command
);
86 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply
.domain_uuid
));
90 "\tIs a GC of the forest: %s\n"
91 "\tIs an LDAP server: %s\n"
93 "\tIs running a KDC: %s\n"
94 "\tIs running time services: %s\n"
95 "\tIs the closest DC: %s\n"
97 "\tHas a hardware clock: %s\n"
98 "\tIs a non-domain NC serviced by LDAP server: %s\n"
99 "\tIs NT6 DC that has some secrets: %s\n"
100 "\tIs NT6 DC that has all secrets: %s\n"),
101 (reply
.server_type
& NBT_SERVER_PDC
) ? _("yes") : _("no"),
102 (reply
.server_type
& NBT_SERVER_GC
) ? _("yes") : _("no"),
103 (reply
.server_type
& NBT_SERVER_LDAP
) ? _("yes") : _("no"),
104 (reply
.server_type
& NBT_SERVER_DS
) ? _("yes") : _("no"),
105 (reply
.server_type
& NBT_SERVER_KDC
) ? _("yes") : _("no"),
106 (reply
.server_type
& NBT_SERVER_TIMESERV
) ? _("yes") : _("no"),
107 (reply
.server_type
& NBT_SERVER_CLOSEST
) ? _("yes") : _("no"),
108 (reply
.server_type
& NBT_SERVER_WRITABLE
) ? _("yes") : _("no"),
109 (reply
.server_type
& NBT_SERVER_GOOD_TIMESERV
) ? _("yes") : _("no"),
110 (reply
.server_type
& NBT_SERVER_NDNC
) ? _("yes") : _("no"),
111 (reply
.server_type
& NBT_SERVER_SELECT_SECRET_DOMAIN_6
) ? _("yes") : _("no"),
112 (reply
.server_type
& NBT_SERVER_FULL_SECRET_DOMAIN_6
) ? _("yes") : _("no"));
115 printf(_("Forest:\t\t\t%s\n"), reply
.forest
);
116 printf(_("Domain:\t\t\t%s\n"), reply
.dns_domain
);
117 printf(_("Domain Controller:\t%s\n"), reply
.pdc_dns_name
);
119 printf(_("Pre-Win2k Domain:\t%s\n"), reply
.domain_name
);
120 printf(_("Pre-Win2k Hostname:\t%s\n"), reply
.pdc_name
);
122 if (*reply
.user_name
) printf(_("User name:\t%s\n"), reply
.user_name
);
124 printf(_("Server Site Name :\t\t%s\n"), reply
.server_site
);
125 printf(_("Client Site Name :\t\t%s\n"), reply
.client_site
);
127 d_printf(_("NT Version: %d\n"), reply
.nt_version
);
128 d_printf(_("LMNT Token: %.2x\n"), reply
.lmnt_token
);
129 d_printf(_("LM20 Token: %.2x\n"), reply
.lm20_token
);
135 this implements the CLDAP based netlogon lookup requests
136 for finding the domain controller of a ADS domain
138 static int net_ads_lookup(struct net_context
*c
, int argc
, const char **argv
)
143 if (c
->display_usage
) {
148 _("Find the ADS DC using CLDAP lookup.\n"));
152 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
153 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
158 if (!ads
->config
.realm
) {
159 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
160 ads
->ldap
.port
= 389;
163 ret
= net_ads_cldap_netlogon(c
, ads
);
170 static int net_ads_info(struct net_context
*c
, int argc
, const char **argv
)
173 char addr
[INET6_ADDRSTRLEN
];
175 if (c
->display_usage
) {
180 _("Display information about an Active Directory "
185 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
186 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
190 if (!ads
|| !ads
->config
.realm
) {
191 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
196 /* Try to set the server's current time since we didn't do a full
197 TCP LDAP session initially */
199 if ( !ADS_ERR_OK(ads_current_time( ads
)) ) {
200 d_fprintf( stderr
, _("Failed to get server's current time!\n"));
203 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
205 d_printf(_("LDAP server: %s\n"), addr
);
206 d_printf(_("LDAP server name: %s\n"), ads
->config
.ldap_server_name
);
207 d_printf(_("Realm: %s\n"), ads
->config
.realm
);
208 d_printf(_("Bind Path: %s\n"), ads
->config
.bind_path
);
209 d_printf(_("LDAP port: %d\n"), ads
->ldap
.port
);
210 d_printf(_("Server time: %s\n"),
211 http_timestring(talloc_tos(), ads
->config
.current_time
));
213 d_printf(_("KDC server: %s\n"), ads
->auth
.kdc_server
);
214 d_printf(_("Server time offset: %d\n"), ads
->auth
.time_offset
);
220 static void use_in_memory_ccache(void) {
221 /* Use in-memory credentials cache so we do not interfere with
222 * existing credentials */
223 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
226 static ADS_STATUS
ads_startup_int(struct net_context
*c
, bool only_own_domain
,
227 uint32 auth_flags
, ADS_STRUCT
**ads_ret
)
229 ADS_STRUCT
*ads
= NULL
;
231 bool need_password
= false;
232 bool second_time
= false;
234 const char *realm
= NULL
;
235 bool tried_closest_dc
= false;
237 /* lp_realm() should be handled by a command line param,
238 However, the join requires that realm be set in smb.conf
239 and compares our realm with the remote server's so this is
240 ok until someone needs more flexibility */
245 if (only_own_domain
) {
248 realm
= assume_own_realm(c
);
251 ads
= ads_init(realm
, c
->opt_target_workgroup
, c
->opt_host
);
253 if (!c
->opt_user_name
) {
254 c
->opt_user_name
= "administrator";
257 if (c
->opt_user_specified
) {
258 need_password
= true;
262 if (!c
->opt_password
&& need_password
&& !c
->opt_machine_pass
) {
263 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
264 if (!c
->opt_password
) {
266 return ADS_ERROR(LDAP_NO_MEMORY
);
270 if (c
->opt_password
) {
271 use_in_memory_ccache();
272 SAFE_FREE(ads
->auth
.password
);
273 ads
->auth
.password
= smb_xstrdup(c
->opt_password
);
276 ads
->auth
.flags
|= auth_flags
;
277 SAFE_FREE(ads
->auth
.user_name
);
278 ads
->auth
.user_name
= smb_xstrdup(c
->opt_user_name
);
281 * If the username is of the form "name@realm",
282 * extract the realm and convert to upper case.
283 * This is only used to establish the connection.
285 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
287 SAFE_FREE(ads
->auth
.realm
);
288 ads
->auth
.realm
= smb_xstrdup(cp
);
289 strupper_m(ads
->auth
.realm
);
292 status
= ads_connect(ads
);
294 if (!ADS_ERR_OK(status
)) {
296 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
297 NT_STATUS_NO_LOGON_SERVERS
)) {
298 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
303 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
304 need_password
= true;
313 /* when contacting our own domain, make sure we use the closest DC.
314 * This is done by reconnecting to ADS because only the first call to
315 * ads_connect will give us our own sitename */
317 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
319 tried_closest_dc
= true; /* avoid loop */
321 if (!ads_closest_dc(ads
)) {
323 namecache_delete(ads
->server
.realm
, 0x1C);
324 namecache_delete(ads
->server
.workgroup
, 0x1C);
337 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
339 return ads_startup_int(c
, only_own_domain
, 0, ads
);
342 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
344 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
348 Check to see if connection can be made via ads.
349 ads_startup() stores the password in opt_password if it needs to so
350 that rpc or rap can use it without re-prompting.
352 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
357 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
361 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
363 status
= ads_connect(ads
);
364 if ( !ADS_ERR_OK(status
) ) {
372 int net_ads_check_our_domain(struct net_context
*c
)
374 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
377 int net_ads_check(struct net_context
*c
)
379 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
383 determine the netbios workgroup name for a domain
385 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
388 char addr
[INET6_ADDRSTRLEN
];
389 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
391 if (c
->display_usage
) {
393 "net ads workgroup\n"
396 _("Print the workgroup name"));
400 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
401 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
405 if (!ads
->config
.realm
) {
406 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
407 ads
->ldap
.port
= 389;
410 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
411 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
412 d_fprintf(stderr
, _("CLDAP query failed!\n"));
417 d_printf(_("Workgroup: %s\n"), reply
.domain_name
);
426 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
428 char **disp_fields
= (char **) data_area
;
430 if (!field
) { /* must be end of record */
431 if (disp_fields
[0]) {
432 if (!strchr_m(disp_fields
[0], '$')) {
434 d_printf("%-21.21s %s\n",
435 disp_fields
[0], disp_fields
[1]);
437 d_printf("%s\n", disp_fields
[0]);
440 SAFE_FREE(disp_fields
[0]);
441 SAFE_FREE(disp_fields
[1]);
444 if (!values
) /* must be new field, indicate string field */
446 if (StrCaseCmp(field
, "sAMAccountName") == 0) {
447 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
449 if (StrCaseCmp(field
, "description") == 0)
450 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
454 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
456 return net_user_usage(c
, argc
, argv
);
459 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
464 LDAPMessage
*res
=NULL
;
468 if (argc
< 1 || c
->display_usage
)
469 return net_ads_user_usage(c
, argc
, argv
);
471 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
475 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
477 if (!ADS_ERR_OK(status
)) {
478 d_fprintf(stderr
, _("ads_user_add: %s\n"), ads_errstr(status
));
482 if (ads_count_replies(ads
, res
)) {
483 d_fprintf(stderr
, _("ads_user_add: User %s already exists\n"),
488 if (c
->opt_container
) {
489 ou_str
= SMB_STRDUP(c
->opt_container
);
491 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
494 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
496 if (!ADS_ERR_OK(status
)) {
497 d_fprintf(stderr
, _("Could not add user %s: %s\n"), argv
[0],
502 /* if no password is to be set, we're done */
504 d_printf(_("User %s added\n"), argv
[0]);
509 /* try setting the password */
510 if (asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
) == -1) {
513 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
514 ads
->auth
.time_offset
);
516 if (ADS_ERR_OK(status
)) {
517 d_printf(_("User %s added\n"), argv
[0]);
522 /* password didn't set, delete account */
523 d_fprintf(stderr
, _("Could not add user %s. "
524 "Error setting password %s\n"),
525 argv
[0], ads_errstr(status
));
526 ads_msgfree(ads
, res
);
527 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
528 if (ADS_ERR_OK(status
)) {
529 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
530 ads_del_dn(ads
, userdn
);
536 ads_msgfree(ads
, res
);
542 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
544 ADS_STRUCT
*ads
= NULL
;
546 LDAPMessage
*res
= NULL
;
550 const char *attrs
[] = {"memberOf", "primaryGroupID", NULL
};
551 char *searchstring
=NULL
;
555 struct dom_sid primary_group_sid
;
557 enum wbcSidType type
;
559 if (argc
< 1 || c
->display_usage
) {
560 return net_ads_user_usage(c
, argc
, argv
);
563 frame
= talloc_new(talloc_tos());
568 escaped_user
= escape_ldap_string(frame
, argv
[0]);
571 _("ads_user_info: failed to escape user %s\n"),
576 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
581 if (asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
) == -1) {
585 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
586 SAFE_FREE(searchstring
);
588 if (!ADS_ERR_OK(rc
)) {
589 d_fprintf(stderr
, _("ads_search: %s\n"), ads_errstr(rc
));
594 if (!ads_pull_uint32(ads
, res
, "primaryGroupID", &group_rid
)) {
595 d_fprintf(stderr
, _("ads_pull_uint32 failed\n"));
600 rc
= ads_domain_sid(ads
, &primary_group_sid
);
601 if (!ADS_ERR_OK(rc
)) {
602 d_fprintf(stderr
, _("ads_domain_sid: %s\n"), ads_errstr(rc
));
607 sid_append_rid(&primary_group_sid
, group_rid
);
609 wbc_status
= wbcLookupSid((struct wbcDomainSid
*)&primary_group_sid
,
610 NULL
, /* don't look up domain */
613 if (!WBC_ERROR_IS_OK(wbc_status
)) {
614 d_fprintf(stderr
, "wbcLookupSid: %s\n",
615 wbcErrorString(wbc_status
));
620 d_printf("%s\n", primary_group
);
622 wbcFreeMemory(primary_group
);
624 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
625 (LDAPMessage
*)res
, "memberOf");
630 for (i
=0;grouplist
[i
];i
++) {
631 groupname
= ldap_explode_dn(grouplist
[i
], 1);
632 d_printf("%s\n", groupname
[0]);
633 ldap_value_free(groupname
);
635 ldap_value_free(grouplist
);
639 if (res
) ads_msgfree(ads
, res
);
640 if (ads
) ads_destroy(&ads
);
645 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
649 LDAPMessage
*res
= NULL
;
653 return net_ads_user_usage(c
, argc
, argv
);
656 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
660 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
661 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
662 d_printf(_("User %s does not exist.\n"), argv
[0]);
663 ads_msgfree(ads
, res
);
667 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
668 ads_msgfree(ads
, res
);
669 rc
= ads_del_dn(ads
, userdn
);
671 if (ADS_ERR_OK(rc
)) {
672 d_printf(_("User %s deleted\n"), argv
[0]);
676 d_fprintf(stderr
, _("Error deleting user %s: %s\n"), argv
[0],
682 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
684 struct functable func
[] = {
689 N_("Add an AD user"),
690 N_("net ads user add\n"
697 N_("Display information about an AD user"),
698 N_("net ads user info\n"
699 " Display information about an AD user")
705 N_("Delete an AD user"),
706 N_("net ads user delete\n"
707 " Delete an AD user")
709 {NULL
, NULL
, 0, NULL
, NULL
}
713 const char *shortattrs
[] = {"sAMAccountName", NULL
};
714 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
715 char *disp_fields
[2] = {NULL
, NULL
};
718 if (c
->display_usage
) {
724 net_display_usage_from_functable(func
);
728 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
732 if (c
->opt_long_list_entries
)
733 d_printf(_("\nUser name Comment"
734 "\n-----------------------------\n"));
736 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
738 "(objectCategory=user)",
739 c
->opt_long_list_entries
? longattrs
:
740 shortattrs
, usergrp_display
,
743 return ADS_ERR_OK(rc
) ? 0 : -1;
746 return net_run_function(c
, argc
, argv
, "net ads user", func
);
749 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
751 return net_group_usage(c
, argc
, argv
);
754 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
758 LDAPMessage
*res
=NULL
;
762 if (argc
< 1 || c
->display_usage
) {
763 return net_ads_group_usage(c
, argc
, argv
);
766 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
770 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
772 if (!ADS_ERR_OK(status
)) {
773 d_fprintf(stderr
, _("ads_group_add: %s\n"), ads_errstr(status
));
777 if (ads_count_replies(ads
, res
)) {
778 d_fprintf(stderr
, _("ads_group_add: Group %s already exists\n"), argv
[0]);
782 if (c
->opt_container
) {
783 ou_str
= SMB_STRDUP(c
->opt_container
);
785 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
788 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
790 if (ADS_ERR_OK(status
)) {
791 d_printf(_("Group %s added\n"), argv
[0]);
794 d_fprintf(stderr
, _("Could not add group %s: %s\n"), argv
[0],
800 ads_msgfree(ads
, res
);
806 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
810 LDAPMessage
*res
= NULL
;
813 if (argc
< 1 || c
->display_usage
) {
814 return net_ads_group_usage(c
, argc
, argv
);
817 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
821 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
822 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
823 d_printf(_("Group %s does not exist.\n"), argv
[0]);
824 ads_msgfree(ads
, res
);
828 groupdn
= ads_get_dn(ads
, talloc_tos(), res
);
829 ads_msgfree(ads
, res
);
830 rc
= ads_del_dn(ads
, groupdn
);
831 TALLOC_FREE(groupdn
);
832 if (ADS_ERR_OK(rc
)) {
833 d_printf(_("Group %s deleted\n"), argv
[0]);
837 d_fprintf(stderr
, _("Error deleting group %s: %s\n"), argv
[0],
843 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
845 struct functable func
[] = {
850 N_("Add an AD group"),
851 N_("net ads group add\n"
858 N_("Delete an AD group"),
859 N_("net ads group delete\n"
860 " Delete an AD group")
862 {NULL
, NULL
, 0, NULL
, NULL
}
866 const char *shortattrs
[] = {"sAMAccountName", NULL
};
867 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
868 char *disp_fields
[2] = {NULL
, NULL
};
871 if (c
->display_usage
) {
876 _("List AD groups"));
877 net_display_usage_from_functable(func
);
881 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
885 if (c
->opt_long_list_entries
)
886 d_printf(_("\nGroup name Comment"
887 "\n-----------------------------\n"));
888 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
890 "(objectCategory=group)",
891 c
->opt_long_list_entries
? longattrs
:
892 shortattrs
, usergrp_display
,
896 return ADS_ERR_OK(rc
) ? 0 : -1;
898 return net_run_function(c
, argc
, argv
, "net ads group", func
);
901 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
907 if (c
->display_usage
) {
912 _("Display machine account details"));
916 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
920 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
921 if (!ADS_ERR_OK(rc
)) {
922 d_fprintf(stderr
, _("ads_find_machine_acct: %s\n"), ads_errstr(rc
));
927 if (ads_count_replies(ads
, res
) == 0) {
928 d_fprintf(stderr
, _("No machine account for '%s' found\n"), global_myname());
938 /*******************************************************************
939 Leave an AD domain. Windows XP disables the machine account.
940 We'll try the same. The old code would do an LDAP delete.
941 That only worked using the machine creds because added the machine
942 with full control to the computer object's ACL.
943 *******************************************************************/
945 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
948 struct libnet_UnjoinCtx
*r
= NULL
;
951 if (c
->display_usage
) {
956 _("Leave an AD domain"));
961 d_fprintf(stderr
, _("No realm set, are we joined ?\n"));
965 if (!(ctx
= talloc_init("net_ads_leave"))) {
966 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
970 if (!c
->opt_kerberos
) {
971 use_in_memory_ccache();
975 d_fprintf(stderr
, _("Could not initialise message context. "
976 "Try running as root\n"));
980 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
981 if (!W_ERROR_IS_OK(werr
)) {
982 d_fprintf(stderr
, _("Could not initialise unjoin context.\n"));
987 r
->in
.use_kerberos
= c
->opt_kerberos
;
988 r
->in
.dc_name
= c
->opt_host
;
989 r
->in
.domain_name
= lp_realm();
990 r
->in
.admin_account
= c
->opt_user_name
;
991 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
992 r
->in
.modify_config
= lp_config_backend_is_registry();
994 /* Try to delete it, but if that fails, disable it. The
995 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
996 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
997 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
998 r
->in
.delete_machine_account
= true;
999 r
->in
.msg_ctx
= c
->msg_ctx
;
1001 werr
= libnet_Unjoin(ctx
, r
);
1002 if (!W_ERROR_IS_OK(werr
)) {
1003 d_printf(_("Failed to leave domain: %s\n"),
1004 r
->out
.error_string
? r
->out
.error_string
:
1005 get_friendly_werror_msg(werr
));
1009 if (r
->out
.deleted_machine_account
) {
1010 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1011 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1015 /* We couldn't delete it - see if the disable succeeded. */
1016 if (r
->out
.disabled_machine_account
) {
1017 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1018 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1023 /* Based on what we requseted, we shouldn't get here, but if
1024 we did, it means the secrets were removed, and therefore
1025 we have left the domain */
1026 d_fprintf(stderr
, _("Machine '%s' Left domain '%s'\n"),
1027 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1033 if (W_ERROR_IS_OK(werr
)) {
1040 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
1042 ADS_STRUCT
*ads
= NULL
;
1045 struct sockaddr_storage dcip
;
1047 if (!secrets_init()) {
1048 DEBUG(1,("Failed to initialise secrets database\n"));
1049 return NT_STATUS_ACCESS_DENIED
;
1052 net_use_krb_machine_account(c
);
1054 get_dc_name(lp_workgroup(), lp_realm(), dc_name
, &dcip
);
1056 status
= ads_startup(c
, true, &ads
);
1057 if (!ADS_ERR_OK(status
)) {
1058 return ads_ntstatus(status
);
1062 return NT_STATUS_OK
;
1066 check that an existing join is OK
1068 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
1071 use_in_memory_ccache();
1073 if (c
->display_usage
) {
1075 "net ads testjoin\n"
1078 _("Test if the existing join is ok"));
1082 /* Display success or failure */
1083 status
= net_ads_join_ok(c
);
1084 if (!NT_STATUS_IS_OK(status
)) {
1085 fprintf(stderr
, _("Join to domain is not valid: %s\n"),
1086 get_friendly_nt_error_msg(status
));
1090 printf(_("Join is OK\n"));
1094 /*******************************************************************
1095 Simple configu checks before beginning the join
1096 ********************************************************************/
1098 static WERROR
check_ads_config( void )
1100 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
1101 d_printf(_("Host is not configured as a member server.\n"));
1102 return WERR_INVALID_DOMAIN_ROLE
;
1105 if (strlen(global_myname()) > 15) {
1106 d_printf(_("Our netbios name can be at most 15 chars long, "
1107 "\"%s\" is %u chars long\n"), global_myname(),
1108 (unsigned int)strlen(global_myname()));
1109 return WERR_INVALID_COMPUTERNAME
;
1112 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1113 d_fprintf(stderr
, _("realm must be set in in %s for ADS "
1114 "join to succeed.\n"), get_dyn_CONFIGFILE());
1115 return WERR_INVALID_PARAM
;
1121 /*******************************************************************
1122 Send a DNS update request
1123 *******************************************************************/
1125 #if defined(WITH_DNS_UPDATES)
1126 #include "../lib/addns/dns.h"
1128 static NTSTATUS
net_update_dns_internal(struct net_context
*c
,
1129 TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1130 const char *machine_name
,
1131 const struct sockaddr_storage
*addrs
,
1134 struct dns_rr_ns
*nameservers
= NULL
;
1135 int ns_count
= 0, i
;
1136 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1139 const char *dnsdomain
= NULL
;
1140 char *root_domain
= NULL
;
1142 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1143 d_printf(_("No DNS domain configured for %s. "
1144 "Unable to perform DNS Update.\n"), machine_name
);
1145 status
= NT_STATUS_INVALID_PARAMETER
;
1150 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
1151 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1152 /* Child domains often do not have NS records. Look
1153 for the NS record for the forest root domain
1154 (rootDomainNamingContext in therootDSE) */
1156 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1157 LDAPMessage
*msg
= NULL
;
1159 ADS_STATUS ads_status
;
1161 if ( !ads
->ldap
.ld
) {
1162 ads_status
= ads_connect( ads
);
1163 if ( !ADS_ERR_OK(ads_status
) ) {
1164 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1169 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1170 "(objectclass=*)", rootname_attrs
, &msg
);
1171 if (!ADS_ERR_OK(ads_status
)) {
1175 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1177 ads_msgfree( ads
, msg
);
1181 root_domain
= ads_build_domain( root_dn
);
1184 ads_msgfree( ads
, msg
);
1186 /* try again for NS servers */
1188 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1190 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1191 DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
1192 "realm\n", ads
->config
.realm
));
1196 dnsdomain
= root_domain
;
1200 for (i
=0; i
< ns_count
; i
++) {
1202 uint32_t flags
= DNS_UPDATE_SIGNED
|
1203 DNS_UPDATE_UNSIGNED
|
1204 DNS_UPDATE_UNSIGNED_SUFFICIENT
|
1206 DNS_UPDATE_PROBE_SUFFICIENT
;
1209 flags
&= ~DNS_UPDATE_PROBE_SUFFICIENT
;
1210 flags
&= ~DNS_UPDATE_UNSIGNED_SUFFICIENT
;
1213 status
= NT_STATUS_UNSUCCESSFUL
;
1215 /* Now perform the dns update - we'll try non-secure and if we fail,
1216 we'll follow it up with a secure update */
1218 fstrcpy( dns_server
, nameservers
[i
].hostname
);
1220 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
, flags
);
1221 if (ERR_DNS_IS_OK(dns_err
)) {
1222 status
= NT_STATUS_OK
;
1226 if (ERR_DNS_EQUAL(dns_err
, ERROR_DNS_INVALID_NAME_SERVER
) ||
1227 ERR_DNS_EQUAL(dns_err
, ERROR_DNS_CONNECTION_FAILED
) ||
1228 ERR_DNS_EQUAL(dns_err
, ERROR_DNS_SOCKET_ERROR
)) {
1229 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1230 dns_errstr(dns_err
)));
1234 d_printf(_("DNS Update for %s failed: %s\n"),
1235 machine_name
, dns_errstr(dns_err
));
1236 status
= NT_STATUS_UNSUCCESSFUL
;
1242 SAFE_FREE( root_domain
);
1247 static NTSTATUS
net_update_dns_ext(struct net_context
*c
,
1248 TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
,
1249 const char *hostname
,
1250 struct sockaddr_storage
*iplist
,
1253 struct sockaddr_storage
*iplist_alloc
= NULL
;
1254 fstring machine_name
;
1258 fstrcpy(machine_name
, hostname
);
1260 name_to_fqdn( machine_name
, global_myname() );
1262 strlower_m( machine_name
);
1264 if (num_addrs
== 0 || iplist
== NULL
) {
1266 * Get our ip address
1267 * (not the 127.0.0.x address but a real ip address)
1269 num_addrs
= get_my_ip_address(&iplist_alloc
);
1270 if ( num_addrs
<= 0 ) {
1271 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1272 "non-loopback IP addresses!\n"));
1273 return NT_STATUS_INVALID_PARAMETER
;
1275 iplist
= iplist_alloc
;
1278 status
= net_update_dns_internal(c
, mem_ctx
, ads
, machine_name
,
1281 SAFE_FREE(iplist_alloc
);
1285 static NTSTATUS
net_update_dns(struct net_context
*c
, TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
, const char *hostname
)
1289 status
= net_update_dns_ext(c
, mem_ctx
, ads
, hostname
, NULL
, 0);
1295 /*******************************************************************
1296 ********************************************************************/
1298 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1300 d_printf(_("net ads join [options]\n"
1301 "Valid options:\n"));
1302 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1303 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1304 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1305 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1306 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1307 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1308 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1309 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1310 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1311 " NB: osName and osVer must be specified together for either to take effect.\n"
1312 " Also, the operatingSystemService attribute is also set when along with\n"
1313 " the two other attributes.\n"));
1318 /*******************************************************************
1319 ********************************************************************/
1321 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1323 TALLOC_CTX
*ctx
= NULL
;
1324 struct libnet_JoinCtx
*r
= NULL
;
1325 const char *domain
= lp_realm();
1326 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1327 bool createupn
= false;
1328 const char *machineupn
= NULL
;
1329 const char *create_in_ou
= NULL
;
1331 const char *os_name
= NULL
;
1332 const char *os_version
= NULL
;
1333 bool modify_config
= lp_config_backend_is_registry();
1335 if (c
->display_usage
)
1336 return net_ads_join_usage(c
, argc
, argv
);
1338 if (!modify_config
) {
1340 werr
= check_ads_config();
1341 if (!W_ERROR_IS_OK(werr
)) {
1342 d_fprintf(stderr
, _("Invalid configuration. Exiting....\n"));
1347 if (!(ctx
= talloc_init("net_ads_join"))) {
1348 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
1353 if (!c
->opt_kerberos
) {
1354 use_in_memory_ccache();
1357 werr
= libnet_init_JoinCtx(ctx
, &r
);
1358 if (!W_ERROR_IS_OK(werr
)) {
1362 /* process additional command line args */
1364 for ( i
=0; i
<argc
; i
++ ) {
1365 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1367 machineupn
= get_string_param(argv
[i
]);
1369 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1370 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1371 d_fprintf(stderr
, _("Please supply a valid OU path.\n"));
1372 werr
= WERR_INVALID_PARAM
;
1376 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1377 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1378 d_fprintf(stderr
, _("Please supply a operating system name.\n"));
1379 werr
= WERR_INVALID_PARAM
;
1383 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1384 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1385 d_fprintf(stderr
, _("Please supply a valid operating system version.\n"));
1386 werr
= WERR_INVALID_PARAM
;
1396 d_fprintf(stderr
, _("Please supply a valid domain name\n"));
1397 werr
= WERR_INVALID_PARAM
;
1402 d_fprintf(stderr
, _("Could not initialise message context. "
1403 "Try running as root\n"));
1404 werr
= WERR_ACCESS_DENIED
;
1408 /* Do the domain join here */
1410 r
->in
.domain_name
= domain
;
1411 r
->in
.create_upn
= createupn
;
1412 r
->in
.upn
= machineupn
;
1413 r
->in
.account_ou
= create_in_ou
;
1414 r
->in
.os_name
= os_name
;
1415 r
->in
.os_version
= os_version
;
1416 r
->in
.dc_name
= c
->opt_host
;
1417 r
->in
.admin_account
= c
->opt_user_name
;
1418 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1420 r
->in
.use_kerberos
= c
->opt_kerberos
;
1421 r
->in
.modify_config
= modify_config
;
1422 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1423 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1424 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1425 r
->in
.msg_ctx
= c
->msg_ctx
;
1427 werr
= libnet_Join(ctx
, r
);
1428 if (W_ERROR_EQUAL(werr
, WERR_DCNOTFOUND
) &&
1429 strequal(domain
, lp_realm())) {
1430 r
->in
.domain_name
= lp_workgroup();
1431 werr
= libnet_Join(ctx
, r
);
1433 if (!W_ERROR_IS_OK(werr
)) {
1437 /* Check the short name of the domain */
1439 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1440 d_printf(_("The workgroup in %s does not match the short\n"
1441 "domain name obtained from the server.\n"
1442 "Using the name [%s] from the server.\n"
1443 "You should set \"workgroup = %s\" in %s.\n"),
1444 get_dyn_CONFIGFILE(), r
->out
.netbios_domain_name
,
1445 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1448 d_printf(_("Using short domain name -- %s\n"), r
->out
.netbios_domain_name
);
1450 if (r
->out
.dns_domain_name
) {
1451 d_printf(_("Joined '%s' to dns domain '%s'\n"), r
->in
.machine_name
,
1452 r
->out
.dns_domain_name
);
1454 d_printf(_("Joined '%s' to domain '%s'\n"), r
->in
.machine_name
,
1455 r
->out
.netbios_domain_name
);
1458 #if defined(WITH_DNS_UPDATES)
1460 * In a clustered environment, don't do dynamic dns updates:
1461 * Registering the set of ip addresses that are assigned to
1462 * the interfaces of the node that performs the join does usually
1463 * not have the desired effect, since the local interfaces do not
1464 * carry the complete set of the cluster's public IP addresses.
1465 * And it can also contain internal addresses that should not
1466 * be visible to the outside at all.
1467 * In order to do dns updates in a clustererd setup, use
1468 * net ads dns register.
1470 if (lp_clustering()) {
1471 d_fprintf(stderr
, _("Not doing automatic DNS update in a"
1472 "clustered setup.\n"));
1476 if (r
->out
.domain_is_ad
) {
1477 /* We enter this block with user creds */
1478 ADS_STRUCT
*ads_dns
= NULL
;
1480 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1481 /* kinit with the machine password */
1483 use_in_memory_ccache();
1484 if (asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname()) == -1) {
1487 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1488 r
->out
.netbios_domain_name
, NULL
, NULL
);
1489 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1490 strupper_m(ads_dns
->auth
.realm
);
1491 ads_kinit_password( ads_dns
);
1494 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns(c
, ctx
, ads_dns
, NULL
)) ) {
1495 d_fprintf( stderr
, _("DNS update failed!\n") );
1498 /* exit from this block using machine creds */
1499 ads_destroy(&ads_dns
);
1511 /* issue an overall failure message at the end. */
1512 d_printf(_("Failed to join domain: %s\n"),
1513 r
&& r
->out
.error_string
? r
->out
.error_string
:
1514 get_friendly_werror_msg(werr
));
1520 /*******************************************************************
1521 ********************************************************************/
1523 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1525 #if defined(WITH_DNS_UPDATES)
1530 const char *hostname
= NULL
;
1531 const char **addrs_list
= NULL
;
1532 struct sockaddr_storage
*addrs
= NULL
;
1537 talloc_enable_leak_report();
1540 if (argc
<= 1 && lp_clustering() && lp_cluster_addresses() == NULL
) {
1541 d_fprintf(stderr
, _("Refusing DNS updates with automatic "
1542 "detection of addresses in a clustered "
1544 c
->display_usage
= true;
1547 if (c
->display_usage
) {
1549 "net ads dns register [hostname [IP [IP...]]]\n"
1552 _("Register hostname with DNS\n"));
1556 if (!(ctx
= talloc_init("net_ads_dns"))) {
1557 d_fprintf(stderr
, _("Could not initialise talloc context\n"));
1566 num_addrs
= argc
- 1;
1567 addrs_list
= &argv
[1];
1568 } else if (lp_clustering()) {
1569 addrs_list
= lp_cluster_addresses();
1570 num_addrs
= str_list_length(addrs_list
);
1573 if (num_addrs
> 0) {
1574 addrs
= talloc_zero_array(ctx
, struct sockaddr_storage
, num_addrs
);
1575 if (addrs
== NULL
) {
1576 d_fprintf(stderr
, _("Error allocating memory!\n"));
1582 for (count
= 0; count
< num_addrs
; count
++) {
1583 if (!interpret_string_addr(&addrs
[count
], addrs_list
[count
], 0)) {
1584 d_fprintf(stderr
, "%s '%s'.\n",
1585 _("Cannot interpret address"),
1592 status
= ads_startup(c
, true, &ads
);
1593 if ( !ADS_ERR_OK(status
) ) {
1594 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1599 ntstatus
= net_update_dns_ext(c
, ctx
, ads
, hostname
, addrs
, num_addrs
);
1600 if (!NT_STATUS_IS_OK(ntstatus
)) {
1601 d_fprintf( stderr
, _("DNS update failed!\n") );
1602 ads_destroy( &ads
);
1607 d_fprintf( stderr
, _("Successfully registered hostname with DNS\n") );
1615 _("DNS update support not enabled at compile time!\n"));
1620 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1622 #if defined(WITH_DNS_UPDATES)
1626 talloc_enable_leak_report();
1629 if (argc
!= 2 || c
->display_usage
) {
1634 _("net ads dns gethostbyname <server> <name>\n"),
1635 _(" Look up hostname from the AD\n"
1636 " server\tName server to use\n"
1637 " name\tName to look up\n"));
1641 err
= do_gethostbyname(argv
[0], argv
[1]);
1643 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1644 dns_errstr(err
), ERROR_DNS_V(err
));
1649 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1651 struct functable func
[] = {
1654 net_ads_dns_register
,
1656 N_("Add host dns entry to AD"),
1657 N_("net ads dns register\n"
1658 " Add host dns entry to AD")
1662 net_ads_dns_gethostbyname
,
1665 N_("net ads dns gethostbyname\n"
1668 {NULL
, NULL
, 0, NULL
, NULL
}
1671 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1674 /*******************************************************************
1675 ********************************************************************/
1677 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1680 "\nnet ads printer search <printer>"
1681 "\n\tsearch for a printer in the directory\n"
1682 "\nnet ads printer info <printer> <server>"
1683 "\n\tlookup info in directory for printer on server"
1684 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1685 "\nnet ads printer publish <printername>"
1686 "\n\tpublish printer in directory"
1687 "\n\t(note: printer name is required)\n"
1688 "\nnet ads printer remove <printername>"
1689 "\n\tremove printer from directory"
1690 "\n\t(note: printer name is required)\n"));
1694 /*******************************************************************
1695 ********************************************************************/
1697 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1701 LDAPMessage
*res
= NULL
;
1703 if (c
->display_usage
) {
1705 "net ads printer search\n"
1708 _("List printers in the AD"));
1712 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1716 rc
= ads_find_printers(ads
, &res
);
1718 if (!ADS_ERR_OK(rc
)) {
1719 d_fprintf(stderr
, _("ads_find_printer: %s\n"), ads_errstr(rc
));
1720 ads_msgfree(ads
, res
);
1725 if (ads_count_replies(ads
, res
) == 0) {
1726 d_fprintf(stderr
, _("No results found\n"));
1727 ads_msgfree(ads
, res
);
1733 ads_msgfree(ads
, res
);
1738 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1742 const char *servername
, *printername
;
1743 LDAPMessage
*res
= NULL
;
1745 if (c
->display_usage
) {
1748 _("net ads printer info [printername [servername]]\n"
1749 " Display printer info from AD\n"
1750 " printername\tPrinter name or wildcard\n"
1751 " servername\tName of the print server\n"));
1755 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1760 printername
= argv
[0];
1766 servername
= argv
[1];
1768 servername
= global_myname();
1771 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1773 if (!ADS_ERR_OK(rc
)) {
1774 d_fprintf(stderr
, _("Server '%s' not found: %s\n"),
1775 servername
, ads_errstr(rc
));
1776 ads_msgfree(ads
, res
);
1781 if (ads_count_replies(ads
, res
) == 0) {
1782 d_fprintf(stderr
, _("Printer '%s' not found\n"), printername
);
1783 ads_msgfree(ads
, res
);
1789 ads_msgfree(ads
, res
);
1795 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1799 const char *servername
, *printername
;
1800 struct cli_state
*cli
= NULL
;
1801 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1802 struct sockaddr_storage server_ss
;
1804 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1805 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1806 char *prt_dn
, *srv_dn
, **srv_cn
;
1807 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1808 LDAPMessage
*res
= NULL
;
1810 if (argc
< 1 || c
->display_usage
) {
1813 _("net ads printer publish <printername> [servername]\n"
1814 " Publish printer in AD\n"
1815 " printername\tName of the printer\n"
1816 " servername\tName of the print server\n"));
1817 talloc_destroy(mem_ctx
);
1821 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1822 talloc_destroy(mem_ctx
);
1826 printername
= argv
[0];
1829 servername
= argv
[1];
1831 servername
= global_myname();
1834 /* Get printer data from SPOOLSS */
1836 resolve_name(servername
, &server_ss
, 0x20, false);
1838 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1841 c
->opt_user_name
, c
->opt_workgroup
,
1842 c
->opt_password
? c
->opt_password
: "",
1843 CLI_FULL_CONNECTION_USE_KERBEROS
,
1846 if (NT_STATUS_IS_ERR(nt_status
)) {
1847 d_fprintf(stderr
, _("Unable to open a connection to %s to "
1848 "obtain data for %s\n"),
1849 servername
, printername
);
1851 talloc_destroy(mem_ctx
);
1855 /* Publish on AD server */
1857 ads_find_machine_acct(ads
, &res
, servername
);
1859 if (ads_count_replies(ads
, res
) == 0) {
1860 d_fprintf(stderr
, _("Could not find machine account for server "
1864 talloc_destroy(mem_ctx
);
1868 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1869 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1871 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1872 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1873 if (!srv_cn_escaped
|| !printername_escaped
) {
1874 SAFE_FREE(srv_cn_escaped
);
1875 SAFE_FREE(printername_escaped
);
1876 d_fprintf(stderr
, _("Internal error, out of memory!"));
1878 talloc_destroy(mem_ctx
);
1882 if (asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
) == -1) {
1883 SAFE_FREE(srv_cn_escaped
);
1884 SAFE_FREE(printername_escaped
);
1885 d_fprintf(stderr
, _("Internal error, out of memory!"));
1887 talloc_destroy(mem_ctx
);
1891 SAFE_FREE(srv_cn_escaped
);
1892 SAFE_FREE(printername_escaped
);
1894 nt_status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_spoolss
.syntax_id
, &pipe_hnd
);
1895 if (!NT_STATUS_IS_OK(nt_status
)) {
1896 d_fprintf(stderr
, _("Unable to open a connection to the spoolss pipe on %s\n"),
1900 talloc_destroy(mem_ctx
);
1904 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1908 talloc_destroy(mem_ctx
);
1912 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1913 if (!ADS_ERR_OK(rc
)) {
1914 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1917 talloc_destroy(mem_ctx
);
1921 d_printf("published printer\n");
1924 talloc_destroy(mem_ctx
);
1929 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1933 const char *servername
;
1935 LDAPMessage
*res
= NULL
;
1937 if (argc
< 1 || c
->display_usage
) {
1940 _("net ads printer remove <printername> [servername]\n"
1941 " Remove a printer from the AD\n"
1942 " printername\tName of the printer\n"
1943 " servername\tName of the print server\n"));
1947 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1952 servername
= argv
[1];
1954 servername
= global_myname();
1957 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1959 if (!ADS_ERR_OK(rc
)) {
1960 d_fprintf(stderr
, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc
));
1961 ads_msgfree(ads
, res
);
1966 if (ads_count_replies(ads
, res
) == 0) {
1967 d_fprintf(stderr
, _("Printer '%s' not found\n"), argv
[1]);
1968 ads_msgfree(ads
, res
);
1973 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
1974 ads_msgfree(ads
, res
);
1975 rc
= ads_del_dn(ads
, prt_dn
);
1976 TALLOC_FREE(prt_dn
);
1978 if (!ADS_ERR_OK(rc
)) {
1979 d_fprintf(stderr
, _("ads_del_dn: %s\n"), ads_errstr(rc
));
1988 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
1990 struct functable func
[] = {
1993 net_ads_printer_search
,
1995 N_("Search for a printer"),
1996 N_("net ads printer search\n"
1997 " Search for a printer")
2001 net_ads_printer_info
,
2003 N_("Display printer information"),
2004 N_("net ads printer info\n"
2005 " Display printer information")
2009 net_ads_printer_publish
,
2011 N_("Publish a printer"),
2012 N_("net ads printer publish\n"
2013 " Publish a printer")
2017 net_ads_printer_remove
,
2019 N_("Delete a printer"),
2020 N_("net ads printer remove\n"
2021 " Delete a printer")
2023 {NULL
, NULL
, 0, NULL
, NULL
}
2026 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
2030 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
2033 const char *auth_principal
= c
->opt_user_name
;
2034 const char *auth_password
= c
->opt_password
;
2036 char *new_password
= NULL
;
2041 if (c
->display_usage
) {
2044 _("net ads password <username>\n"
2045 " Change password for user\n"
2046 " username\tName of user to change password for\n"));
2050 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
2051 d_fprintf(stderr
, _("You must supply an administrator "
2052 "username/password\n"));
2057 d_fprintf(stderr
, _("ERROR: You must say which username to "
2058 "change password for\n"));
2063 if (!strchr_m(user
, '@')) {
2064 if (asprintf(&chr
, "%s@%s", argv
[0], lp_realm()) == -1) {
2070 use_in_memory_ccache();
2071 chr
= strchr_m(auth_principal
, '@');
2078 /* use the realm so we can eventually change passwords for users
2079 in realms other than default */
2080 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
2084 /* we don't actually need a full connect, but it's the easy way to
2085 fill in the KDC's addresss */
2088 if (!ads
->config
.realm
) {
2089 d_fprintf(stderr
, _("Didn't find the kerberos server!\n"));
2095 new_password
= (char *)argv
[1];
2097 if (asprintf(&prompt
, _("Enter new password for %s:"), user
) == -1) {
2100 new_password
= getpass(prompt
);
2104 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
2105 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
2106 if (!ADS_ERR_OK(ret
)) {
2107 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2112 d_printf(_("Password change for %s completed.\n"), user
);
2118 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2121 char *host_principal
;
2125 if (c
->display_usage
) {
2127 "net ads changetrustpw\n"
2130 _("Change the machine account's trust password"));
2134 if (!secrets_init()) {
2135 DEBUG(1,("Failed to initialise secrets database\n"));
2139 net_use_krb_machine_account(c
);
2141 use_in_memory_ccache();
2143 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2147 fstrcpy(my_name
, global_myname());
2148 strlower_m(my_name
);
2149 if (asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
) == -1) {
2153 d_printf(_("Changing password for principal: %s\n"), host_principal
);
2155 ret
= ads_change_trust_account_password(ads
, host_principal
);
2157 if (!ADS_ERR_OK(ret
)) {
2158 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2160 SAFE_FREE(host_principal
);
2164 d_printf(_("Password change for principal %s succeeded.\n"), host_principal
);
2166 if (USE_SYSTEM_KEYTAB
) {
2167 d_printf(_("Attempting to update system keytab with new password.\n"));
2168 if (ads_keytab_create_default(ads
)) {
2169 d_printf(_("Failed to update system keytab.\n"));
2174 SAFE_FREE(host_principal
);
2180 help for net ads search
2182 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
2185 "\nnet ads search <expression> <attributes...>\n"
2186 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2187 "The expression is a standard LDAP search expression, and the\n"
2188 "attributes are a list of LDAP fields to show in the results.\n\n"
2189 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2191 net_common_flags_usage(c
, argc
, argv
);
2197 general ADS search function. Useful in diagnosing problems in ADS
2199 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
2203 const char *ldap_exp
;
2205 LDAPMessage
*res
= NULL
;
2207 if (argc
< 1 || c
->display_usage
) {
2208 return net_ads_search_usage(c
, argc
, argv
);
2211 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2218 rc
= ads_do_search_retry(ads
, ads
->config
.bind_path
,
2220 ldap_exp
, attrs
, &res
);
2221 if (!ADS_ERR_OK(rc
)) {
2222 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2227 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2229 /* dump the results */
2232 ads_msgfree(ads
, res
);
2240 help for net ads search
2242 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
2245 "\nnet ads dn <dn> <attributes...>\n"
2246 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2247 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2248 "to show in the results\n\n"
2249 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2250 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2252 net_common_flags_usage(c
, argc
, argv
);
2258 general ADS search function. Useful in diagnosing problems in ADS
2260 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
2266 LDAPMessage
*res
= NULL
;
2268 if (argc
< 1 || c
->display_usage
) {
2269 return net_ads_dn_usage(c
, argc
, argv
);
2272 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2279 rc
= ads_do_search_all(ads
, dn
,
2281 "(objectclass=*)", attrs
, &res
);
2282 if (!ADS_ERR_OK(rc
)) {
2283 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2288 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2290 /* dump the results */
2293 ads_msgfree(ads
, res
);
2300 help for net ads sid search
2302 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2305 "\nnet ads sid <sid> <attributes...>\n"
2306 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2307 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2308 "to show in the results\n\n"
2309 "Example: net ads sid 'S-1-5-32' distinguishedName\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_sid(struct net_context
*c
, int argc
, const char **argv
)
2323 const char *sid_string
;
2325 LDAPMessage
*res
= NULL
;
2328 if (argc
< 1 || c
->display_usage
) {
2329 return net_ads_sid_usage(c
, argc
, argv
);
2332 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2336 sid_string
= argv
[0];
2339 if (!string_to_sid(&sid
, sid_string
)) {
2340 d_fprintf(stderr
, _("could not convert sid\n"));
2345 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2346 if (!ADS_ERR_OK(rc
)) {
2347 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2352 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2354 /* dump the results */
2357 ads_msgfree(ads
, res
);
2363 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2368 if (c
->display_usage
) {
2370 "net ads keytab flush\n"
2373 _("Delete the whole keytab"));
2377 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2380 ret
= ads_keytab_flush(ads
);
2385 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2391 if (c
->display_usage
) {
2394 _("net ads keytab add <principal> [principal ...]\n"
2395 " Add principals to local keytab\n"
2396 " principal\tKerberos principal to add to "
2401 d_printf(_("Processing principals to add...\n"));
2402 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2405 for (i
= 0; i
< argc
; i
++) {
2406 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2412 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2417 if (c
->display_usage
) {
2419 "net ads keytab create\n"
2422 _("Create new default keytab"));
2426 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2429 ret
= ads_keytab_create_default(ads
);
2434 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2436 const char *keytab
= NULL
;
2438 if (c
->display_usage
) {
2441 _("net ads keytab list [keytab]\n"
2442 " List a local keytab\n"
2443 " keytab\tKeytab to list\n"));
2451 return ads_keytab_list(keytab
);
2455 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2457 struct functable func
[] = {
2462 N_("Add a service principal"),
2463 N_("net ads keytab add\n"
2464 " Add a service principal")
2468 net_ads_keytab_create
,
2470 N_("Create a fresh keytab"),
2471 N_("net ads keytab create\n"
2472 " Create a fresh keytab")
2476 net_ads_keytab_flush
,
2478 N_("Remove all keytab entries"),
2479 N_("net ads keytab flush\n"
2480 " Remove all keytab entries")
2484 net_ads_keytab_list
,
2486 N_("List a keytab"),
2487 N_("net ads keytab list\n"
2490 {NULL
, NULL
, 0, NULL
, NULL
}
2493 if (!USE_KERBEROS_KEYTAB
) {
2494 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2495 "keytab method to use keytab functions.\n"));
2498 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2501 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2505 if (c
->display_usage
) {
2507 "net ads kerberos renew\n"
2510 _("Renew TGT from existing credential cache"));
2514 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2516 d_printf(_("failed to renew kerberos ticket: %s\n"),
2517 error_message(ret
));
2522 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2524 struct PAC_LOGON_INFO
*info
= NULL
;
2525 TALLOC_CTX
*mem_ctx
= NULL
;
2528 const char *impersonate_princ_s
= NULL
;
2530 if (c
->display_usage
) {
2532 "net ads kerberos pac\n"
2535 _("Dump the Kerberos PAC"));
2539 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2545 impersonate_princ_s
= argv
[0];
2548 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2550 status
= kerberos_return_pac(mem_ctx
,
2559 2592000, /* one month */
2560 impersonate_princ_s
,
2562 if (!NT_STATUS_IS_OK(status
)) {
2563 d_printf(_("failed to query kerberos PAC: %s\n"),
2570 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2571 d_printf(_("The Pac: %s\n"), s
);
2576 TALLOC_FREE(mem_ctx
);
2580 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2582 TALLOC_CTX
*mem_ctx
= NULL
;
2586 if (c
->display_usage
) {
2588 "net ads kerberos kinit\n"
2591 _("Get Ticket Granting Ticket (TGT) for the user"));
2595 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2600 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2602 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2610 2592000, /* one month */
2613 d_printf(_("failed to kinit password: %s\n"),
2620 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2622 struct functable func
[] = {
2625 net_ads_kerberos_kinit
,
2627 N_("Retrieve Ticket Granting Ticket (TGT)"),
2628 N_("net ads kerberos kinit\n"
2629 " Receive Ticket Granting Ticket (TGT)")
2633 net_ads_kerberos_renew
,
2635 N_("Renew Ticket Granting Ticket from credential cache"),
2636 N_("net ads kerberos renew\n"
2637 " Renew Ticket Granting Ticket (TGT) from "
2642 net_ads_kerberos_pac
,
2644 N_("Dump Kerberos PAC"),
2645 N_("net ads kerberos pac\n"
2646 " Dump Kerberos PAC")
2648 {NULL
, NULL
, 0, NULL
, NULL
}
2651 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2654 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2656 struct functable func
[] = {
2661 N_("Display details on remote ADS server"),
2663 " Display details on remote ADS server")
2669 N_("Join the local machine to ADS realm"),
2671 " Join the local machine to ADS realm")
2677 N_("Validate machine account"),
2678 N_("net ads testjoin\n"
2679 " Validate machine account")
2685 N_("Remove the local machine from ADS"),
2686 N_("net ads leave\n"
2687 " Remove the local machine from ADS")
2693 N_("Display machine account details"),
2694 N_("net ads status\n"
2695 " Display machine account details")
2701 N_("List/modify users"),
2703 " List/modify users")
2709 N_("List/modify groups"),
2710 N_("net ads group\n"
2711 " List/modify groups")
2717 N_("Issue dynamic DNS update"),
2719 " Issue dynamic DNS update")
2725 N_("Change user passwords"),
2726 N_("net ads password\n"
2727 " Change user passwords")
2731 net_ads_changetrustpw
,
2733 N_("Change trust account password"),
2734 N_("net ads changetrustpw\n"
2735 " Change trust account password")
2741 N_("List/modify printer entries"),
2742 N_("net ads printer\n"
2743 " List/modify printer entries")
2749 N_("Issue LDAP search using filter"),
2750 N_("net ads search\n"
2751 " Issue LDAP search using filter")
2757 N_("Issue LDAP search by DN"),
2759 " Issue LDAP search by DN")
2765 N_("Issue LDAP search by SID"),
2767 " Issue LDAP search by SID")
2773 N_("Display workgroup name"),
2774 N_("net ads workgroup\n"
2775 " Display the workgroup name")
2781 N_("Perfom CLDAP query on DC"),
2782 N_("net ads lookup\n"
2783 " Find the ADS DC using CLDAP lookups")
2789 N_("Manage local keytab file"),
2790 N_("net ads keytab\n"
2791 " Manage local keytab file")
2797 N_("Manage group policy objects"),
2799 " Manage group policy objects")
2805 N_("Manage kerberos keytab"),
2806 N_("net ads kerberos\n"
2807 " Manage kerberos keytab")
2809 {NULL
, NULL
, 0, NULL
, NULL
}
2812 return net_run_function(c
, argc
, argv
, "net ads", func
);
2817 static int net_ads_noads(void)
2819 d_fprintf(stderr
, _("ADS support not compiled in\n"));
2823 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2825 return net_ads_noads();
2828 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2830 return net_ads_noads();
2833 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2835 return net_ads_noads();
2838 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2840 return net_ads_noads();
2843 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2845 return net_ads_noads();
2848 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2850 return net_ads_noads();
2853 int net_ads_gpo(struct net_context
*c
, int argc
, const char **argv
)
2855 return net_ads_noads();
2858 /* this one shouldn't display a message */
2859 int net_ads_check(struct net_context
*c
)
2864 int net_ads_check_our_domain(struct net_context
*c
)
2869 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2871 return net_ads_noads();
2874 #endif /* WITH_ADS */