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"
43 /* when we do not have sufficient input parameters to contact a remote domain
44 * we always fall back to our own realm - Guenther*/
46 static const char *assume_own_realm(struct net_context
*c
)
48 if (!c
->opt_host
&& strequal(lp_workgroup(), c
->opt_target_workgroup
)) {
56 do a cldap netlogon query
58 static int net_ads_cldap_netlogon(struct net_context
*c
, ADS_STRUCT
*ads
)
60 char addr
[INET6_ADDRSTRLEN
];
61 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
63 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
64 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
65 d_fprintf(stderr
, _("CLDAP query failed!\n"));
69 d_printf(_("Information for Domain Controller: %s\n\n"),
72 d_printf(_("Response Type: "));
73 switch (reply
.command
) {
74 case LOGON_SAM_LOGON_USER_UNKNOWN_EX
:
75 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
77 case LOGON_SAM_LOGON_RESPONSE_EX
:
78 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
81 d_printf("0x%x\n", reply
.command
);
85 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply
.domain_uuid
));
89 "\tIs a GC of the forest: %s\n"
90 "\tIs an LDAP server: %s\n"
92 "\tIs running a KDC: %s\n"
93 "\tIs running time services: %s\n"
94 "\tIs the closest DC: %s\n"
96 "\tHas a hardware clock: %s\n"
97 "\tIs a non-domain NC serviced by LDAP server: %s\n"
98 "\tIs NT6 DC that has some secrets: %s\n"
99 "\tIs NT6 DC that has all secrets: %s\n"),
100 (reply
.server_type
& NBT_SERVER_PDC
) ? _("yes") : _("no"),
101 (reply
.server_type
& NBT_SERVER_GC
) ? _("yes") : _("no"),
102 (reply
.server_type
& NBT_SERVER_LDAP
) ? _("yes") : _("no"),
103 (reply
.server_type
& NBT_SERVER_DS
) ? _("yes") : _("no"),
104 (reply
.server_type
& NBT_SERVER_KDC
) ? _("yes") : _("no"),
105 (reply
.server_type
& NBT_SERVER_TIMESERV
) ? _("yes") : _("no"),
106 (reply
.server_type
& NBT_SERVER_CLOSEST
) ? _("yes") : _("no"),
107 (reply
.server_type
& NBT_SERVER_WRITABLE
) ? _("yes") : _("no"),
108 (reply
.server_type
& NBT_SERVER_GOOD_TIMESERV
) ? _("yes") : _("no"),
109 (reply
.server_type
& NBT_SERVER_NDNC
) ? _("yes") : _("no"),
110 (reply
.server_type
& NBT_SERVER_SELECT_SECRET_DOMAIN_6
) ? _("yes") : _("no"),
111 (reply
.server_type
& NBT_SERVER_FULL_SECRET_DOMAIN_6
) ? _("yes") : _("no"));
114 printf(_("Forest:\t\t\t%s\n"), reply
.forest
);
115 printf(_("Domain:\t\t\t%s\n"), reply
.dns_domain
);
116 printf(_("Domain Controller:\t%s\n"), reply
.pdc_dns_name
);
118 printf(_("Pre-Win2k Domain:\t%s\n"), reply
.domain_name
);
119 printf(_("Pre-Win2k Hostname:\t%s\n"), reply
.pdc_name
);
121 if (*reply
.user_name
) printf(_("User name:\t%s\n"), reply
.user_name
);
123 printf(_("Server Site Name :\t\t%s\n"), reply
.server_site
);
124 printf(_("Client Site Name :\t\t%s\n"), reply
.client_site
);
126 d_printf(_("NT Version: %d\n"), reply
.nt_version
);
127 d_printf(_("LMNT Token: %.2x\n"), reply
.lmnt_token
);
128 d_printf(_("LM20 Token: %.2x\n"), reply
.lm20_token
);
134 this implements the CLDAP based netlogon lookup requests
135 for finding the domain controller of a ADS domain
137 static int net_ads_lookup(struct net_context
*c
, int argc
, const char **argv
)
142 if (c
->display_usage
) {
147 _("Find the ADS DC using CLDAP lookup.\n"));
151 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
152 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
157 if (!ads
->config
.realm
) {
158 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
159 ads
->ldap
.port
= 389;
162 ret
= net_ads_cldap_netlogon(c
, ads
);
169 static int net_ads_info(struct net_context
*c
, int argc
, const char **argv
)
172 char addr
[INET6_ADDRSTRLEN
];
174 if (c
->display_usage
) {
179 _("Display information about an Active Directory "
184 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
185 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
189 if (!ads
|| !ads
->config
.realm
) {
190 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
195 /* Try to set the server's current time since we didn't do a full
196 TCP LDAP session initially */
198 if ( !ADS_ERR_OK(ads_current_time( ads
)) ) {
199 d_fprintf( stderr
, _("Failed to get server's current time!\n"));
202 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
204 d_printf(_("LDAP server: %s\n"), addr
);
205 d_printf(_("LDAP server name: %s\n"), ads
->config
.ldap_server_name
);
206 d_printf(_("Realm: %s\n"), ads
->config
.realm
);
207 d_printf(_("Bind Path: %s\n"), ads
->config
.bind_path
);
208 d_printf(_("LDAP port: %d\n"), ads
->ldap
.port
);
209 d_printf(_("Server time: %s\n"),
210 http_timestring(talloc_tos(), ads
->config
.current_time
));
212 d_printf(_("KDC server: %s\n"), ads
->auth
.kdc_server
);
213 d_printf(_("Server time offset: %d\n"), ads
->auth
.time_offset
);
219 static void use_in_memory_ccache(void) {
220 /* Use in-memory credentials cache so we do not interfere with
221 * existing credentials */
222 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
225 static ADS_STATUS
ads_startup_int(struct net_context
*c
, bool only_own_domain
,
226 uint32 auth_flags
, ADS_STRUCT
**ads_ret
)
228 ADS_STRUCT
*ads
= NULL
;
230 bool need_password
= false;
231 bool second_time
= false;
233 const char *realm
= NULL
;
234 bool tried_closest_dc
= false;
236 /* lp_realm() should be handled by a command line param,
237 However, the join requires that realm be set in smb.conf
238 and compares our realm with the remote server's so this is
239 ok until someone needs more flexibility */
244 if (only_own_domain
) {
247 realm
= assume_own_realm(c
);
250 ads
= ads_init(realm
, c
->opt_target_workgroup
, c
->opt_host
);
252 if (!c
->opt_user_name
) {
253 c
->opt_user_name
= "administrator";
256 if (c
->opt_user_specified
) {
257 need_password
= true;
261 if (!c
->opt_password
&& need_password
&& !c
->opt_machine_pass
) {
262 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
263 if (!c
->opt_password
) {
265 return ADS_ERROR(LDAP_NO_MEMORY
);
269 if (c
->opt_password
) {
270 use_in_memory_ccache();
271 SAFE_FREE(ads
->auth
.password
);
272 ads
->auth
.password
= smb_xstrdup(c
->opt_password
);
275 ads
->auth
.flags
|= auth_flags
;
276 SAFE_FREE(ads
->auth
.user_name
);
277 ads
->auth
.user_name
= smb_xstrdup(c
->opt_user_name
);
280 * If the username is of the form "name@realm",
281 * extract the realm and convert to upper case.
282 * This is only used to establish the connection.
284 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
286 SAFE_FREE(ads
->auth
.realm
);
287 ads
->auth
.realm
= smb_xstrdup(cp
);
288 strupper_m(ads
->auth
.realm
);
291 status
= ads_connect(ads
);
293 if (!ADS_ERR_OK(status
)) {
295 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
296 NT_STATUS_NO_LOGON_SERVERS
)) {
297 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
302 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
303 need_password
= true;
312 /* when contacting our own domain, make sure we use the closest DC.
313 * This is done by reconnecting to ADS because only the first call to
314 * ads_connect will give us our own sitename */
316 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
318 tried_closest_dc
= true; /* avoid loop */
320 if (!ads_closest_dc(ads
)) {
322 namecache_delete(ads
->server
.realm
, 0x1C);
323 namecache_delete(ads
->server
.workgroup
, 0x1C);
336 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
338 return ads_startup_int(c
, only_own_domain
, 0, ads
);
341 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
343 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
347 Check to see if connection can be made via ads.
348 ads_startup() stores the password in opt_password if it needs to so
349 that rpc or rap can use it without re-prompting.
351 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
356 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
360 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
362 status
= ads_connect(ads
);
363 if ( !ADS_ERR_OK(status
) ) {
371 int net_ads_check_our_domain(struct net_context
*c
)
373 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
376 int net_ads_check(struct net_context
*c
)
378 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
382 determine the netbios workgroup name for a domain
384 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
387 char addr
[INET6_ADDRSTRLEN
];
388 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
390 if (c
->display_usage
) {
392 "net ads workgroup\n"
395 _("Print the workgroup name"));
399 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
400 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
404 if (!ads
->config
.realm
) {
405 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
406 ads
->ldap
.port
= 389;
409 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
410 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
411 d_fprintf(stderr
, _("CLDAP query failed!\n"));
416 d_printf(_("Workgroup: %s\n"), reply
.domain_name
);
425 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
427 char **disp_fields
= (char **) data_area
;
429 if (!field
) { /* must be end of record */
430 if (disp_fields
[0]) {
431 if (!strchr_m(disp_fields
[0], '$')) {
433 d_printf("%-21.21s %s\n",
434 disp_fields
[0], disp_fields
[1]);
436 d_printf("%s\n", disp_fields
[0]);
439 SAFE_FREE(disp_fields
[0]);
440 SAFE_FREE(disp_fields
[1]);
443 if (!values
) /* must be new field, indicate string field */
445 if (StrCaseCmp(field
, "sAMAccountName") == 0) {
446 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
448 if (StrCaseCmp(field
, "description") == 0)
449 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
453 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
455 return net_user_usage(c
, argc
, argv
);
458 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
463 LDAPMessage
*res
=NULL
;
467 if (argc
< 1 || c
->display_usage
)
468 return net_ads_user_usage(c
, argc
, argv
);
470 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
474 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
476 if (!ADS_ERR_OK(status
)) {
477 d_fprintf(stderr
, _("ads_user_add: %s\n"), ads_errstr(status
));
481 if (ads_count_replies(ads
, res
)) {
482 d_fprintf(stderr
, _("ads_user_add: User %s already exists\n"),
487 if (c
->opt_container
) {
488 ou_str
= SMB_STRDUP(c
->opt_container
);
490 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
493 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
495 if (!ADS_ERR_OK(status
)) {
496 d_fprintf(stderr
, _("Could not add user %s: %s\n"), argv
[0],
501 /* if no password is to be set, we're done */
503 d_printf(_("User %s added\n"), argv
[0]);
508 /* try setting the password */
509 if (asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
) == -1) {
512 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
513 ads
->auth
.time_offset
);
515 if (ADS_ERR_OK(status
)) {
516 d_printf(_("User %s added\n"), argv
[0]);
521 /* password didn't set, delete account */
522 d_fprintf(stderr
, _("Could not add user %s. "
523 "Error setting password %s\n"),
524 argv
[0], ads_errstr(status
));
525 ads_msgfree(ads
, res
);
526 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
527 if (ADS_ERR_OK(status
)) {
528 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
529 ads_del_dn(ads
, userdn
);
535 ads_msgfree(ads
, res
);
541 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
543 ADS_STRUCT
*ads
= NULL
;
545 LDAPMessage
*res
= NULL
;
549 const char *attrs
[] = {"memberOf", "primaryGroupID", NULL
};
550 char *searchstring
=NULL
;
554 struct dom_sid primary_group_sid
;
556 enum wbcSidType type
;
558 if (argc
< 1 || c
->display_usage
) {
559 return net_ads_user_usage(c
, argc
, argv
);
562 frame
= talloc_new(talloc_tos());
567 escaped_user
= escape_ldap_string(frame
, argv
[0]);
570 _("ads_user_info: failed to escape user %s\n"),
575 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
580 if (asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
) == -1) {
584 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
585 SAFE_FREE(searchstring
);
587 if (!ADS_ERR_OK(rc
)) {
588 d_fprintf(stderr
, _("ads_search: %s\n"), ads_errstr(rc
));
593 if (!ads_pull_uint32(ads
, res
, "primaryGroupID", &group_rid
)) {
594 d_fprintf(stderr
, _("ads_pull_uint32 failed\n"));
599 rc
= ads_domain_sid(ads
, &primary_group_sid
);
600 if (!ADS_ERR_OK(rc
)) {
601 d_fprintf(stderr
, _("ads_domain_sid: %s\n"), ads_errstr(rc
));
606 sid_append_rid(&primary_group_sid
, group_rid
);
608 wbc_status
= wbcLookupSid((struct wbcDomainSid
*)&primary_group_sid
,
609 NULL
, /* don't look up domain */
612 if (!WBC_ERROR_IS_OK(wbc_status
)) {
613 d_fprintf(stderr
, "wbcLookupSid: %s\n",
614 wbcErrorString(wbc_status
));
619 d_printf("%s\n", primary_group
);
621 wbcFreeMemory(primary_group
);
623 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
624 (LDAPMessage
*)res
, "memberOf");
629 for (i
=0;grouplist
[i
];i
++) {
630 groupname
= ldap_explode_dn(grouplist
[i
], 1);
631 d_printf("%s\n", groupname
[0]);
632 ldap_value_free(groupname
);
634 ldap_value_free(grouplist
);
638 if (res
) ads_msgfree(ads
, res
);
639 if (ads
) ads_destroy(&ads
);
644 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
648 LDAPMessage
*res
= NULL
;
652 return net_ads_user_usage(c
, argc
, argv
);
655 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
659 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
660 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
661 d_printf(_("User %s does not exist.\n"), argv
[0]);
662 ads_msgfree(ads
, res
);
666 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
667 ads_msgfree(ads
, res
);
668 rc
= ads_del_dn(ads
, userdn
);
670 if (ADS_ERR_OK(rc
)) {
671 d_printf(_("User %s deleted\n"), argv
[0]);
675 d_fprintf(stderr
, _("Error deleting user %s: %s\n"), argv
[0],
681 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
683 struct functable func
[] = {
688 N_("Add an AD user"),
689 N_("net ads user add\n"
696 N_("Display information about an AD user"),
697 N_("net ads user info\n"
698 " Display information about an AD user")
704 N_("Delete an AD user"),
705 N_("net ads user delete\n"
706 " Delete an AD user")
708 {NULL
, NULL
, 0, NULL
, NULL
}
712 const char *shortattrs
[] = {"sAMAccountName", NULL
};
713 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
714 char *disp_fields
[2] = {NULL
, NULL
};
717 if (c
->display_usage
) {
723 net_display_usage_from_functable(func
);
727 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
731 if (c
->opt_long_list_entries
)
732 d_printf(_("\nUser name Comment"
733 "\n-----------------------------\n"));
735 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
737 "(objectCategory=user)",
738 c
->opt_long_list_entries
? longattrs
:
739 shortattrs
, usergrp_display
,
742 return ADS_ERR_OK(rc
) ? 0 : -1;
745 return net_run_function(c
, argc
, argv
, "net ads user", func
);
748 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
750 return net_group_usage(c
, argc
, argv
);
753 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
757 LDAPMessage
*res
=NULL
;
761 if (argc
< 1 || c
->display_usage
) {
762 return net_ads_group_usage(c
, argc
, argv
);
765 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
769 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
771 if (!ADS_ERR_OK(status
)) {
772 d_fprintf(stderr
, _("ads_group_add: %s\n"), ads_errstr(status
));
776 if (ads_count_replies(ads
, res
)) {
777 d_fprintf(stderr
, _("ads_group_add: Group %s already exists\n"), argv
[0]);
781 if (c
->opt_container
) {
782 ou_str
= SMB_STRDUP(c
->opt_container
);
784 ou_str
= ads_default_ou_string(ads
, DS_GUID_USERS_CONTAINER
);
787 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
789 if (ADS_ERR_OK(status
)) {
790 d_printf(_("Group %s added\n"), argv
[0]);
793 d_fprintf(stderr
, _("Could not add group %s: %s\n"), argv
[0],
799 ads_msgfree(ads
, res
);
805 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
809 LDAPMessage
*res
= NULL
;
812 if (argc
< 1 || c
->display_usage
) {
813 return net_ads_group_usage(c
, argc
, argv
);
816 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
820 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
821 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
822 d_printf(_("Group %s does not exist.\n"), argv
[0]);
823 ads_msgfree(ads
, res
);
827 groupdn
= ads_get_dn(ads
, talloc_tos(), res
);
828 ads_msgfree(ads
, res
);
829 rc
= ads_del_dn(ads
, groupdn
);
830 TALLOC_FREE(groupdn
);
831 if (ADS_ERR_OK(rc
)) {
832 d_printf(_("Group %s deleted\n"), argv
[0]);
836 d_fprintf(stderr
, _("Error deleting group %s: %s\n"), argv
[0],
842 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
844 struct functable func
[] = {
849 N_("Add an AD group"),
850 N_("net ads group add\n"
857 N_("Delete an AD group"),
858 N_("net ads group delete\n"
859 " Delete an AD group")
861 {NULL
, NULL
, 0, NULL
, NULL
}
865 const char *shortattrs
[] = {"sAMAccountName", NULL
};
866 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
867 char *disp_fields
[2] = {NULL
, NULL
};
870 if (c
->display_usage
) {
875 _("List AD groups"));
876 net_display_usage_from_functable(func
);
880 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
884 if (c
->opt_long_list_entries
)
885 d_printf(_("\nGroup name Comment"
886 "\n-----------------------------\n"));
887 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
889 "(objectCategory=group)",
890 c
->opt_long_list_entries
? longattrs
:
891 shortattrs
, usergrp_display
,
895 return ADS_ERR_OK(rc
) ? 0 : -1;
897 return net_run_function(c
, argc
, argv
, "net ads group", func
);
900 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
906 if (c
->display_usage
) {
911 _("Display machine account details"));
915 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
919 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
920 if (!ADS_ERR_OK(rc
)) {
921 d_fprintf(stderr
, _("ads_find_machine_acct: %s\n"), ads_errstr(rc
));
926 if (ads_count_replies(ads
, res
) == 0) {
927 d_fprintf(stderr
, _("No machine account for '%s' found\n"), global_myname());
937 /*******************************************************************
938 Leave an AD domain. Windows XP disables the machine account.
939 We'll try the same. The old code would do an LDAP delete.
940 That only worked using the machine creds because added the machine
941 with full control to the computer object's ACL.
942 *******************************************************************/
944 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
947 struct libnet_UnjoinCtx
*r
= NULL
;
950 if (c
->display_usage
) {
955 _("Leave an AD domain"));
960 d_fprintf(stderr
, _("No realm set, are we joined ?\n"));
964 if (!(ctx
= talloc_init("net_ads_leave"))) {
965 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
969 if (!c
->opt_kerberos
) {
970 use_in_memory_ccache();
974 d_fprintf(stderr
, _("Could not initialise message context. "
975 "Try running as root\n"));
979 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
980 if (!W_ERROR_IS_OK(werr
)) {
981 d_fprintf(stderr
, _("Could not initialise unjoin context.\n"));
986 r
->in
.use_kerberos
= c
->opt_kerberos
;
987 r
->in
.dc_name
= c
->opt_host
;
988 r
->in
.domain_name
= lp_realm();
989 r
->in
.admin_account
= c
->opt_user_name
;
990 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
991 r
->in
.modify_config
= lp_config_backend_is_registry();
993 /* Try to delete it, but if that fails, disable it. The
994 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
995 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
996 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
997 r
->in
.delete_machine_account
= true;
998 r
->in
.msg_ctx
= c
->msg_ctx
;
1000 werr
= libnet_Unjoin(ctx
, r
);
1001 if (!W_ERROR_IS_OK(werr
)) {
1002 d_printf(_("Failed to leave domain: %s\n"),
1003 r
->out
.error_string
? r
->out
.error_string
:
1004 get_friendly_werror_msg(werr
));
1008 if (r
->out
.deleted_machine_account
) {
1009 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1010 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1014 /* We couldn't delete it - see if the disable succeeded. */
1015 if (r
->out
.disabled_machine_account
) {
1016 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1017 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1022 /* Based on what we requseted, we shouldn't get here, but if
1023 we did, it means the secrets were removed, and therefore
1024 we have left the domain */
1025 d_fprintf(stderr
, _("Machine '%s' Left domain '%s'\n"),
1026 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1032 if (W_ERROR_IS_OK(werr
)) {
1039 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
1041 ADS_STRUCT
*ads
= NULL
;
1044 struct sockaddr_storage dcip
;
1046 if (!secrets_init()) {
1047 DEBUG(1,("Failed to initialise secrets database\n"));
1048 return NT_STATUS_ACCESS_DENIED
;
1051 net_use_krb_machine_account(c
);
1053 get_dc_name(lp_workgroup(), lp_realm(), dc_name
, &dcip
);
1055 status
= ads_startup(c
, true, &ads
);
1056 if (!ADS_ERR_OK(status
)) {
1057 return ads_ntstatus(status
);
1061 return NT_STATUS_OK
;
1065 check that an existing join is OK
1067 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
1070 use_in_memory_ccache();
1072 if (c
->display_usage
) {
1074 "net ads testjoin\n"
1077 _("Test if the existing join is ok"));
1081 /* Display success or failure */
1082 status
= net_ads_join_ok(c
);
1083 if (!NT_STATUS_IS_OK(status
)) {
1084 fprintf(stderr
, _("Join to domain is not valid: %s\n"),
1085 get_friendly_nt_error_msg(status
));
1089 printf(_("Join is OK\n"));
1093 /*******************************************************************
1094 Simple configu checks before beginning the join
1095 ********************************************************************/
1097 static WERROR
check_ads_config( void )
1099 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
1100 d_printf(_("Host is not configured as a member server.\n"));
1101 return WERR_INVALID_DOMAIN_ROLE
;
1104 if (strlen(global_myname()) > 15) {
1105 d_printf(_("Our netbios name can be at most 15 chars long, "
1106 "\"%s\" is %u chars long\n"), global_myname(),
1107 (unsigned int)strlen(global_myname()));
1108 return WERR_INVALID_COMPUTERNAME
;
1111 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1112 d_fprintf(stderr
, _("realm must be set in in %s for ADS "
1113 "join to succeed.\n"), get_dyn_CONFIGFILE());
1114 return WERR_INVALID_PARAM
;
1120 /*******************************************************************
1121 Send a DNS update request
1122 *******************************************************************/
1124 #if defined(WITH_DNS_UPDATES)
1125 #include "../lib/addns/dns.h"
1126 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
1127 const char *pszDomainName
, const char *pszHostName
,
1128 const struct sockaddr_storage
*sslist
,
1131 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1132 const char *machine_name
,
1133 const struct sockaddr_storage
*addrs
,
1136 struct dns_rr_ns
*nameservers
= NULL
;
1137 int ns_count
= 0, i
;
1138 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1141 const char *dnsdomain
= NULL
;
1142 char *root_domain
= NULL
;
1144 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1145 d_printf(_("No DNS domain configured for %s. "
1146 "Unable to perform DNS Update.\n"), machine_name
);
1147 status
= NT_STATUS_INVALID_PARAMETER
;
1152 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
1153 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1154 /* Child domains often do not have NS records. Look
1155 for the NS record for the forest root domain
1156 (rootDomainNamingContext in therootDSE) */
1158 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1159 LDAPMessage
*msg
= NULL
;
1161 ADS_STATUS ads_status
;
1163 if ( !ads
->ldap
.ld
) {
1164 ads_status
= ads_connect( ads
);
1165 if ( !ADS_ERR_OK(ads_status
) ) {
1166 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1171 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1172 "(objectclass=*)", rootname_attrs
, &msg
);
1173 if (!ADS_ERR_OK(ads_status
)) {
1177 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1179 ads_msgfree( ads
, msg
);
1183 root_domain
= ads_build_domain( root_dn
);
1186 ads_msgfree( ads
, msg
);
1188 /* try again for NS servers */
1190 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1192 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1193 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1194 "realm\n", ads
->config
.realm
));
1198 dnsdomain
= root_domain
;
1202 for (i
=0; i
< ns_count
; i
++) {
1204 /* Now perform the dns update - we'll try non-secure and if we fail,
1205 we'll follow it up with a secure update */
1207 fstrcpy( dns_server
, nameservers
[i
].hostname
);
1209 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1210 if (ERR_DNS_IS_OK(dns_err
)) {
1211 status
= NT_STATUS_OK
;
1215 if (ERR_DNS_EQUAL(dns_err
, ERROR_DNS_INVALID_NAME_SERVER
) ||
1216 ERR_DNS_EQUAL(dns_err
, ERROR_DNS_CONNECTION_FAILED
) ||
1217 ERR_DNS_EQUAL(dns_err
, ERROR_DNS_SOCKET_ERROR
)) {
1218 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1219 dns_errstr(dns_err
)));
1223 d_printf(_("DNS Update for %s failed: %s\n"),
1224 machine_name
, dns_errstr(dns_err
));
1225 status
= NT_STATUS_UNSUCCESSFUL
;
1231 SAFE_FREE( root_domain
);
1236 static NTSTATUS
net_update_dns_ext(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
,
1237 const char *hostname
,
1238 struct sockaddr_storage
*iplist
,
1241 struct sockaddr_storage
*iplist_alloc
= NULL
;
1242 fstring machine_name
;
1246 fstrcpy(machine_name
, hostname
);
1248 name_to_fqdn( machine_name
, global_myname() );
1250 strlower_m( machine_name
);
1252 if (num_addrs
== 0 || iplist
== NULL
) {
1254 * Get our ip address
1255 * (not the 127.0.0.x address but a real ip address)
1257 num_addrs
= get_my_ip_address(&iplist_alloc
);
1258 if ( num_addrs
<= 0 ) {
1259 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1260 "non-loopback IP addresses!\n"));
1261 return NT_STATUS_INVALID_PARAMETER
;
1263 iplist
= iplist_alloc
;
1266 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1269 SAFE_FREE(iplist_alloc
);
1273 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
, const char *hostname
)
1277 status
= net_update_dns_ext(mem_ctx
, ads
, hostname
, NULL
, 0);
1283 /*******************************************************************
1284 ********************************************************************/
1286 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1288 d_printf(_("net ads join [options]\n"
1289 "Valid options:\n"));
1290 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1291 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1292 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1293 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1294 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1295 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1296 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1297 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1298 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1299 " NB: osName and osVer must be specified together for either to take effect.\n"
1300 " Also, the operatingSystemService attribute is also set when along with\n"
1301 " the two other attributes.\n"));
1306 /*******************************************************************
1307 ********************************************************************/
1309 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1311 TALLOC_CTX
*ctx
= NULL
;
1312 struct libnet_JoinCtx
*r
= NULL
;
1313 const char *domain
= lp_realm();
1314 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1315 bool createupn
= false;
1316 const char *machineupn
= NULL
;
1317 const char *create_in_ou
= NULL
;
1319 const char *os_name
= NULL
;
1320 const char *os_version
= NULL
;
1321 bool modify_config
= lp_config_backend_is_registry();
1323 if (c
->display_usage
)
1324 return net_ads_join_usage(c
, argc
, argv
);
1326 if (!modify_config
) {
1328 werr
= check_ads_config();
1329 if (!W_ERROR_IS_OK(werr
)) {
1330 d_fprintf(stderr
, _("Invalid configuration. Exiting....\n"));
1335 if (!(ctx
= talloc_init("net_ads_join"))) {
1336 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
1341 if (!c
->opt_kerberos
) {
1342 use_in_memory_ccache();
1345 werr
= libnet_init_JoinCtx(ctx
, &r
);
1346 if (!W_ERROR_IS_OK(werr
)) {
1350 /* process additional command line args */
1352 for ( i
=0; i
<argc
; i
++ ) {
1353 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1355 machineupn
= get_string_param(argv
[i
]);
1357 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1358 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1359 d_fprintf(stderr
, _("Please supply a valid OU path.\n"));
1360 werr
= WERR_INVALID_PARAM
;
1364 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1365 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1366 d_fprintf(stderr
, _("Please supply a operating system name.\n"));
1367 werr
= WERR_INVALID_PARAM
;
1371 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1372 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1373 d_fprintf(stderr
, _("Please supply a valid operating system version.\n"));
1374 werr
= WERR_INVALID_PARAM
;
1384 d_fprintf(stderr
, _("Please supply a valid domain name\n"));
1385 werr
= WERR_INVALID_PARAM
;
1390 d_fprintf(stderr
, _("Could not initialise message context. "
1391 "Try running as root\n"));
1392 werr
= WERR_ACCESS_DENIED
;
1396 /* Do the domain join here */
1398 r
->in
.domain_name
= domain
;
1399 r
->in
.create_upn
= createupn
;
1400 r
->in
.upn
= machineupn
;
1401 r
->in
.account_ou
= create_in_ou
;
1402 r
->in
.os_name
= os_name
;
1403 r
->in
.os_version
= os_version
;
1404 r
->in
.dc_name
= c
->opt_host
;
1405 r
->in
.admin_account
= c
->opt_user_name
;
1406 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1408 r
->in
.use_kerberos
= c
->opt_kerberos
;
1409 r
->in
.modify_config
= modify_config
;
1410 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1411 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1412 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1413 r
->in
.msg_ctx
= c
->msg_ctx
;
1415 werr
= libnet_Join(ctx
, r
);
1416 if (W_ERROR_EQUAL(werr
, WERR_DCNOTFOUND
) &&
1417 strequal(domain
, lp_realm())) {
1418 r
->in
.domain_name
= lp_workgroup();
1419 werr
= libnet_Join(ctx
, r
);
1421 if (!W_ERROR_IS_OK(werr
)) {
1425 /* Check the short name of the domain */
1427 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1428 d_printf(_("The workgroup in %s does not match the short\n"
1429 "domain name obtained from the server.\n"
1430 "Using the name [%s] from the server.\n"
1431 "You should set \"workgroup = %s\" in %s.\n"),
1432 get_dyn_CONFIGFILE(), r
->out
.netbios_domain_name
,
1433 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1436 d_printf(_("Using short domain name -- %s\n"), r
->out
.netbios_domain_name
);
1438 if (r
->out
.dns_domain_name
) {
1439 d_printf(_("Joined '%s' to realm '%s'\n"), r
->in
.machine_name
,
1440 r
->out
.dns_domain_name
);
1442 d_printf(_("Joined '%s' to domain '%s'\n"), r
->in
.machine_name
,
1443 r
->out
.netbios_domain_name
);
1446 #if defined(WITH_DNS_UPDATES)
1448 * In a clustered environment, don't do dynamic dns updates:
1449 * Registering the set of ip addresses that are assigned to
1450 * the interfaces of the node that performs the join does usually
1451 * not have the desired effect, since the local interfaces do not
1452 * carry the complete set of the cluster's public IP addresses.
1453 * And it can also contain internal addresses that should not
1454 * be visible to the outside at all.
1455 * In order to do dns updates in a clustererd setup, use
1456 * net ads dns register.
1458 if (lp_clustering()) {
1459 d_fprintf(stderr
, _("Not doing automatic DNS update in a"
1460 "clustered setup.\n"));
1464 if (r
->out
.domain_is_ad
) {
1465 /* We enter this block with user creds */
1466 ADS_STRUCT
*ads_dns
= NULL
;
1468 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1469 /* kinit with the machine password */
1471 use_in_memory_ccache();
1472 if (asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname()) == -1) {
1475 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1476 r
->out
.netbios_domain_name
, NULL
, NULL
);
1477 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1478 strupper_m(ads_dns
->auth
.realm
);
1479 ads_kinit_password( ads_dns
);
1482 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns( ctx
, ads_dns
, NULL
)) ) {
1483 d_fprintf( stderr
, _("DNS update failed!\n") );
1486 /* exit from this block using machine creds */
1487 ads_destroy(&ads_dns
);
1499 /* issue an overall failure message at the end. */
1500 d_printf(_("Failed to join domain: %s\n"),
1501 r
&& r
->out
.error_string
? r
->out
.error_string
:
1502 get_friendly_werror_msg(werr
));
1508 /*******************************************************************
1509 ********************************************************************/
1511 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1513 #if defined(WITH_DNS_UPDATES)
1518 const char *hostname
= NULL
;
1519 const char **addrs_list
= NULL
;
1520 struct sockaddr_storage
*addrs
= NULL
;
1525 talloc_enable_leak_report();
1528 if (argc
<= 1 && lp_clustering() && lp_cluster_addresses() == NULL
) {
1529 d_fprintf(stderr
, _("Refusing DNS updates with automatic "
1530 "detection of addresses in a clustered "
1532 c
->display_usage
= true;
1535 if (c
->display_usage
) {
1537 "net ads dns register [hostname [IP [IP...]]]\n"
1540 _("Register hostname with DNS\n"));
1544 if (!(ctx
= talloc_init("net_ads_dns"))) {
1545 d_fprintf(stderr
, _("Could not initialise talloc context\n"));
1554 num_addrs
= argc
- 1;
1555 addrs_list
= &argv
[1];
1556 } else if (lp_clustering()) {
1557 addrs_list
= lp_cluster_addresses();
1558 num_addrs
= str_list_length(addrs_list
);
1561 if (num_addrs
> 0) {
1562 addrs
= talloc_zero_array(ctx
, struct sockaddr_storage
, num_addrs
);
1563 if (addrs
== NULL
) {
1564 d_fprintf(stderr
, _("Error allocating memory!\n"));
1570 for (count
= 0; count
< num_addrs
; count
++) {
1571 if (!interpret_string_addr(&addrs
[count
], addrs_list
[count
], 0)) {
1572 d_fprintf(stderr
, "%s '%s'.\n",
1573 _("Cannot interpret address"),
1580 status
= ads_startup(c
, true, &ads
);
1581 if ( !ADS_ERR_OK(status
) ) {
1582 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1587 ntstatus
= net_update_dns_ext(ctx
, ads
, hostname
, addrs
, num_addrs
);
1588 if (!NT_STATUS_IS_OK(ntstatus
)) {
1589 d_fprintf( stderr
, _("DNS update failed!\n") );
1590 ads_destroy( &ads
);
1595 d_fprintf( stderr
, _("Successfully registered hostname with DNS\n") );
1603 _("DNS update support not enabled at compile time!\n"));
1608 #if defined(WITH_DNS_UPDATES)
1609 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1612 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1614 #if defined(WITH_DNS_UPDATES)
1618 talloc_enable_leak_report();
1621 if (argc
!= 2 || c
->display_usage
) {
1626 _("net ads dns gethostbyname <server> <name>\n"),
1627 _(" Look up hostname from the AD\n"
1628 " server\tName server to use\n"
1629 " name\tName to look up\n"));
1633 err
= do_gethostbyname(argv
[0], argv
[1]);
1635 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1636 dns_errstr(err
), ERROR_DNS_V(err
));
1641 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1643 struct functable func
[] = {
1646 net_ads_dns_register
,
1648 N_("Add host dns entry to AD"),
1649 N_("net ads dns register\n"
1650 " Add host dns entry to AD")
1654 net_ads_dns_gethostbyname
,
1657 N_("net ads dns gethostbyname\n"
1660 {NULL
, NULL
, 0, NULL
, NULL
}
1663 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1666 /*******************************************************************
1667 ********************************************************************/
1669 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1672 "\nnet ads printer search <printer>"
1673 "\n\tsearch for a printer in the directory\n"
1674 "\nnet ads printer info <printer> <server>"
1675 "\n\tlookup info in directory for printer on server"
1676 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1677 "\nnet ads printer publish <printername>"
1678 "\n\tpublish printer in directory"
1679 "\n\t(note: printer name is required)\n"
1680 "\nnet ads printer remove <printername>"
1681 "\n\tremove printer from directory"
1682 "\n\t(note: printer name is required)\n"));
1686 /*******************************************************************
1687 ********************************************************************/
1689 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1693 LDAPMessage
*res
= NULL
;
1695 if (c
->display_usage
) {
1697 "net ads printer search\n"
1700 _("List printers in the AD"));
1704 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1708 rc
= ads_find_printers(ads
, &res
);
1710 if (!ADS_ERR_OK(rc
)) {
1711 d_fprintf(stderr
, _("ads_find_printer: %s\n"), ads_errstr(rc
));
1712 ads_msgfree(ads
, res
);
1717 if (ads_count_replies(ads
, res
) == 0) {
1718 d_fprintf(stderr
, _("No results found\n"));
1719 ads_msgfree(ads
, res
);
1725 ads_msgfree(ads
, res
);
1730 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1734 const char *servername
, *printername
;
1735 LDAPMessage
*res
= NULL
;
1737 if (c
->display_usage
) {
1740 _("net ads printer info [printername [servername]]\n"
1741 " Display printer info from AD\n"
1742 " printername\tPrinter name or wildcard\n"
1743 " servername\tName of the print server\n"));
1747 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1752 printername
= argv
[0];
1758 servername
= argv
[1];
1760 servername
= global_myname();
1763 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1765 if (!ADS_ERR_OK(rc
)) {
1766 d_fprintf(stderr
, _("Server '%s' not found: %s\n"),
1767 servername
, ads_errstr(rc
));
1768 ads_msgfree(ads
, res
);
1773 if (ads_count_replies(ads
, res
) == 0) {
1774 d_fprintf(stderr
, _("Printer '%s' not found\n"), printername
);
1775 ads_msgfree(ads
, res
);
1781 ads_msgfree(ads
, res
);
1787 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1791 const char *servername
, *printername
;
1792 struct cli_state
*cli
= NULL
;
1793 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1794 struct sockaddr_storage server_ss
;
1796 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1797 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1798 char *prt_dn
, *srv_dn
, **srv_cn
;
1799 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1800 LDAPMessage
*res
= NULL
;
1802 if (argc
< 1 || c
->display_usage
) {
1805 _("net ads printer publish <printername> [servername]\n"
1806 " Publish printer in AD\n"
1807 " printername\tName of the printer\n"
1808 " servername\tName of the print server\n"));
1809 talloc_destroy(mem_ctx
);
1813 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1814 talloc_destroy(mem_ctx
);
1818 printername
= argv
[0];
1821 servername
= argv
[1];
1823 servername
= global_myname();
1826 /* Get printer data from SPOOLSS */
1828 resolve_name(servername
, &server_ss
, 0x20, false);
1830 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1833 c
->opt_user_name
, c
->opt_workgroup
,
1834 c
->opt_password
? c
->opt_password
: "",
1835 CLI_FULL_CONNECTION_USE_KERBEROS
,
1838 if (NT_STATUS_IS_ERR(nt_status
)) {
1839 d_fprintf(stderr
, _("Unable to open a connection to %s to "
1840 "obtain data for %s\n"),
1841 servername
, printername
);
1843 talloc_destroy(mem_ctx
);
1847 /* Publish on AD server */
1849 ads_find_machine_acct(ads
, &res
, servername
);
1851 if (ads_count_replies(ads
, res
) == 0) {
1852 d_fprintf(stderr
, _("Could not find machine account for server "
1856 talloc_destroy(mem_ctx
);
1860 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1861 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1863 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1864 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1865 if (!srv_cn_escaped
|| !printername_escaped
) {
1866 SAFE_FREE(srv_cn_escaped
);
1867 SAFE_FREE(printername_escaped
);
1868 d_fprintf(stderr
, _("Internal error, out of memory!"));
1870 talloc_destroy(mem_ctx
);
1874 if (asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
) == -1) {
1875 SAFE_FREE(srv_cn_escaped
);
1876 SAFE_FREE(printername_escaped
);
1877 d_fprintf(stderr
, _("Internal error, out of memory!"));
1879 talloc_destroy(mem_ctx
);
1883 SAFE_FREE(srv_cn_escaped
);
1884 SAFE_FREE(printername_escaped
);
1886 nt_status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_spoolss
.syntax_id
, &pipe_hnd
);
1887 if (!NT_STATUS_IS_OK(nt_status
)) {
1888 d_fprintf(stderr
, _("Unable to open a connection to the spoolss pipe on %s\n"),
1892 talloc_destroy(mem_ctx
);
1896 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1900 talloc_destroy(mem_ctx
);
1904 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1905 if (!ADS_ERR_OK(rc
)) {
1906 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1909 talloc_destroy(mem_ctx
);
1913 d_printf("published printer\n");
1916 talloc_destroy(mem_ctx
);
1921 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1925 const char *servername
;
1927 LDAPMessage
*res
= NULL
;
1929 if (argc
< 1 || c
->display_usage
) {
1932 _("net ads printer remove <printername> [servername]\n"
1933 " Remove a printer from the AD\n"
1934 " printername\tName of the printer\n"
1935 " servername\tName of the print server\n"));
1939 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1944 servername
= argv
[1];
1946 servername
= global_myname();
1949 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1951 if (!ADS_ERR_OK(rc
)) {
1952 d_fprintf(stderr
, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc
));
1953 ads_msgfree(ads
, res
);
1958 if (ads_count_replies(ads
, res
) == 0) {
1959 d_fprintf(stderr
, _("Printer '%s' not found\n"), argv
[1]);
1960 ads_msgfree(ads
, res
);
1965 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
1966 ads_msgfree(ads
, res
);
1967 rc
= ads_del_dn(ads
, prt_dn
);
1968 TALLOC_FREE(prt_dn
);
1970 if (!ADS_ERR_OK(rc
)) {
1971 d_fprintf(stderr
, _("ads_del_dn: %s\n"), ads_errstr(rc
));
1980 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
1982 struct functable func
[] = {
1985 net_ads_printer_search
,
1987 N_("Search for a printer"),
1988 N_("net ads printer search\n"
1989 " Search for a printer")
1993 net_ads_printer_info
,
1995 N_("Display printer information"),
1996 N_("net ads printer info\n"
1997 " Display printer information")
2001 net_ads_printer_publish
,
2003 N_("Publish a printer"),
2004 N_("net ads printer publish\n"
2005 " Publish a printer")
2009 net_ads_printer_remove
,
2011 N_("Delete a printer"),
2012 N_("net ads printer remove\n"
2013 " Delete a printer")
2015 {NULL
, NULL
, 0, NULL
, NULL
}
2018 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
2022 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
2025 const char *auth_principal
= c
->opt_user_name
;
2026 const char *auth_password
= c
->opt_password
;
2028 char *new_password
= NULL
;
2033 if (c
->display_usage
) {
2036 _("net ads password <username>\n"
2037 " Change password for user\n"
2038 " username\tName of user to change password for\n"));
2042 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
2043 d_fprintf(stderr
, _("You must supply an administrator "
2044 "username/password\n"));
2049 d_fprintf(stderr
, _("ERROR: You must say which username to "
2050 "change password for\n"));
2055 if (!strchr_m(user
, '@')) {
2056 if (asprintf(&chr
, "%s@%s", argv
[0], lp_realm()) == -1) {
2062 use_in_memory_ccache();
2063 chr
= strchr_m(auth_principal
, '@');
2070 /* use the realm so we can eventually change passwords for users
2071 in realms other than default */
2072 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
2076 /* we don't actually need a full connect, but it's the easy way to
2077 fill in the KDC's addresss */
2080 if (!ads
->config
.realm
) {
2081 d_fprintf(stderr
, _("Didn't find the kerberos server!\n"));
2087 new_password
= (char *)argv
[1];
2089 if (asprintf(&prompt
, _("Enter new password for %s:"), user
) == -1) {
2092 new_password
= getpass(prompt
);
2096 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
2097 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
2098 if (!ADS_ERR_OK(ret
)) {
2099 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2104 d_printf(_("Password change for %s completed.\n"), user
);
2110 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2113 char *host_principal
;
2117 if (c
->display_usage
) {
2119 "net ads changetrustpw\n"
2122 _("Change the machine account's trust password"));
2126 if (!secrets_init()) {
2127 DEBUG(1,("Failed to initialise secrets database\n"));
2131 net_use_krb_machine_account(c
);
2133 use_in_memory_ccache();
2135 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2139 fstrcpy(my_name
, global_myname());
2140 strlower_m(my_name
);
2141 if (asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
) == -1) {
2145 d_printf(_("Changing password for principal: %s\n"), host_principal
);
2147 ret
= ads_change_trust_account_password(ads
, host_principal
);
2149 if (!ADS_ERR_OK(ret
)) {
2150 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
2152 SAFE_FREE(host_principal
);
2156 d_printf(_("Password change for principal %s succeeded.\n"), host_principal
);
2158 if (USE_SYSTEM_KEYTAB
) {
2159 d_printf(_("Attempting to update system keytab with new password.\n"));
2160 if (ads_keytab_create_default(ads
)) {
2161 d_printf(_("Failed to update system keytab.\n"));
2166 SAFE_FREE(host_principal
);
2172 help for net ads search
2174 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
2177 "\nnet ads search <expression> <attributes...>\n"
2178 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2179 "The expression is a standard LDAP search expression, and the\n"
2180 "attributes are a list of LDAP fields to show in the results.\n\n"
2181 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2183 net_common_flags_usage(c
, argc
, argv
);
2189 general ADS search function. Useful in diagnosing problems in ADS
2191 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
2195 const char *ldap_exp
;
2197 LDAPMessage
*res
= NULL
;
2199 if (argc
< 1 || c
->display_usage
) {
2200 return net_ads_search_usage(c
, argc
, argv
);
2203 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2210 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
2212 ldap_exp
, attrs
, &res
);
2213 if (!ADS_ERR_OK(rc
)) {
2214 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2219 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2221 /* dump the results */
2224 ads_msgfree(ads
, res
);
2232 help for net ads search
2234 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
2237 "\nnet ads dn <dn> <attributes...>\n"
2238 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2239 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2240 "to show in the results\n\n"
2241 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2242 "Note: the DN must be provided properly escaped. See RFC 4514 for details\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_dn(struct net_context
*c
, int argc
, const char **argv
)
2258 LDAPMessage
*res
= NULL
;
2260 if (argc
< 1 || c
->display_usage
) {
2261 return net_ads_dn_usage(c
, argc
, argv
);
2264 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2271 rc
= ads_do_search_all(ads
, dn
,
2273 "(objectclass=*)", 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
);
2292 help for net ads sid search
2294 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2297 "\nnet ads sid <sid> <attributes...>\n"
2298 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2299 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2300 "to show in the results\n\n"
2301 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2303 net_common_flags_usage(c
, argc
, argv
);
2309 general ADS search function. Useful in diagnosing problems in ADS
2311 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2315 const char *sid_string
;
2317 LDAPMessage
*res
= NULL
;
2320 if (argc
< 1 || c
->display_usage
) {
2321 return net_ads_sid_usage(c
, argc
, argv
);
2324 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2328 sid_string
= argv
[0];
2331 if (!string_to_sid(&sid
, sid_string
)) {
2332 d_fprintf(stderr
, _("could not convert sid\n"));
2337 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2338 if (!ADS_ERR_OK(rc
)) {
2339 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2344 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2346 /* dump the results */
2349 ads_msgfree(ads
, res
);
2355 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2360 if (c
->display_usage
) {
2362 "net ads keytab flush\n"
2365 _("Delete the whole keytab"));
2369 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2372 ret
= ads_keytab_flush(ads
);
2377 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2383 if (c
->display_usage
) {
2386 _("net ads keytab add <principal> [principal ...]\n"
2387 " Add principals to local keytab\n"
2388 " principal\tKerberos principal to add to "
2393 d_printf(_("Processing principals to add...\n"));
2394 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2397 for (i
= 0; i
< argc
; i
++) {
2398 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2404 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2409 if (c
->display_usage
) {
2411 "net ads keytab create\n"
2414 _("Create new default keytab"));
2418 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2421 ret
= ads_keytab_create_default(ads
);
2426 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2428 const char *keytab
= NULL
;
2430 if (c
->display_usage
) {
2433 _("net ads keytab list [keytab]\n"
2434 " List a local keytab\n"
2435 " keytab\tKeytab to list\n"));
2443 return ads_keytab_list(keytab
);
2447 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2449 struct functable func
[] = {
2454 N_("Add a service principal"),
2455 N_("net ads keytab add\n"
2456 " Add a service principal")
2460 net_ads_keytab_create
,
2462 N_("Create a fresh keytab"),
2463 N_("net ads keytab create\n"
2464 " Create a fresh keytab")
2468 net_ads_keytab_flush
,
2470 N_("Remove all keytab entries"),
2471 N_("net ads keytab flush\n"
2472 " Remove all keytab entries")
2476 net_ads_keytab_list
,
2478 N_("List a keytab"),
2479 N_("net ads keytab list\n"
2482 {NULL
, NULL
, 0, NULL
, NULL
}
2485 if (!USE_KERBEROS_KEYTAB
) {
2486 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2487 "keytab method to use keytab functions.\n"));
2490 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2493 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2497 if (c
->display_usage
) {
2499 "net ads kerberos renew\n"
2502 _("Renew TGT from existing credential cache"));
2506 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2508 d_printf(_("failed to renew kerberos ticket: %s\n"),
2509 error_message(ret
));
2514 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2516 struct PAC_LOGON_INFO
*info
= NULL
;
2517 TALLOC_CTX
*mem_ctx
= NULL
;
2520 const char *impersonate_princ_s
= NULL
;
2522 if (c
->display_usage
) {
2524 "net ads kerberos pac\n"
2527 _("Dump the Kerberos PAC"));
2531 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2537 impersonate_princ_s
= argv
[0];
2540 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2542 status
= kerberos_return_pac(mem_ctx
,
2551 2592000, /* one month */
2552 impersonate_princ_s
,
2554 if (!NT_STATUS_IS_OK(status
)) {
2555 d_printf(_("failed to query kerberos PAC: %s\n"),
2562 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2563 d_printf(_("The Pac: %s\n"), s
);
2568 TALLOC_FREE(mem_ctx
);
2572 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2574 TALLOC_CTX
*mem_ctx
= NULL
;
2578 if (c
->display_usage
) {
2580 "net ads kerberos kinit\n"
2583 _("Get Ticket Granting Ticket (TGT) for the user"));
2587 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2592 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2594 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2602 2592000, /* one month */
2605 d_printf(_("failed to kinit password: %s\n"),
2612 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2614 struct functable func
[] = {
2617 net_ads_kerberos_kinit
,
2619 N_("Retrieve Ticket Granting Ticket (TGT)"),
2620 N_("net ads kerberos kinit\n"
2621 " Receive Ticket Granting Ticket (TGT)")
2625 net_ads_kerberos_renew
,
2627 N_("Renew Ticket Granting Ticket from credential cache"),
2628 N_("net ads kerberos renew\n"
2629 " Renew Ticket Granting Ticket (TGT) from "
2634 net_ads_kerberos_pac
,
2636 N_("Dump Kerberos PAC"),
2637 N_("net ads kerberos pac\n"
2638 " Dump Kerberos PAC")
2640 {NULL
, NULL
, 0, NULL
, NULL
}
2643 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2646 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2648 struct functable func
[] = {
2653 N_("Display details on remote ADS server"),
2655 " Display details on remote ADS server")
2661 N_("Join the local machine to ADS realm"),
2663 " Join the local machine to ADS realm")
2669 N_("Validate machine account"),
2670 N_("net ads testjoin\n"
2671 " Validate machine account")
2677 N_("Remove the local machine from ADS"),
2678 N_("net ads leave\n"
2679 " Remove the local machine from ADS")
2685 N_("Display machine account details"),
2686 N_("net ads status\n"
2687 " Display machine account details")
2693 N_("List/modify users"),
2695 " List/modify users")
2701 N_("List/modify groups"),
2702 N_("net ads group\n"
2703 " List/modify groups")
2709 N_("Issue dynamic DNS update"),
2711 " Issue dynamic DNS update")
2717 N_("Change user passwords"),
2718 N_("net ads password\n"
2719 " Change user passwords")
2723 net_ads_changetrustpw
,
2725 N_("Change trust account password"),
2726 N_("net ads changetrustpw\n"
2727 " Change trust account password")
2733 N_("List/modify printer entries"),
2734 N_("net ads printer\n"
2735 " List/modify printer entries")
2741 N_("Issue LDAP search using filter"),
2742 N_("net ads search\n"
2743 " Issue LDAP search using filter")
2749 N_("Issue LDAP search by DN"),
2751 " Issue LDAP search by DN")
2757 N_("Issue LDAP search by SID"),
2759 " Issue LDAP search by SID")
2765 N_("Display workgroup name"),
2766 N_("net ads workgroup\n"
2767 " Display the workgroup name")
2773 N_("Perfom CLDAP query on DC"),
2774 N_("net ads lookup\n"
2775 " Find the ADS DC using CLDAP lookups")
2781 N_("Manage local keytab file"),
2782 N_("net ads keytab\n"
2783 " Manage local keytab file")
2789 N_("Manage group policy objects"),
2791 " Manage group policy objects")
2797 N_("Manage kerberos keytab"),
2798 N_("net ads kerberos\n"
2799 " Manage kerberos keytab")
2801 {NULL
, NULL
, 0, NULL
, NULL
}
2804 return net_run_function(c
, argc
, argv
, "net ads", func
);
2809 static int net_ads_noads(void)
2811 d_fprintf(stderr
, _("ADS support not compiled in\n"));
2815 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2817 return net_ads_noads();
2820 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2822 return net_ads_noads();
2825 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2827 return net_ads_noads();
2830 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2832 return net_ads_noads();
2835 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2837 return net_ads_noads();
2840 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2842 return net_ads_noads();
2845 int net_ads_gpo(struct net_context
*c
, int argc
, const char **argv
)
2847 return net_ads_noads();
2850 /* this one shouldn't display a message */
2851 int net_ads_check(struct net_context
*c
)
2856 int net_ads_check_our_domain(struct net_context
*c
)
2861 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2863 return net_ads_noads();
2866 #endif /* WITH_ADS */