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 "librpc/gen_ndr/ndr_krb5pac.h"
26 #include "../librpc/gen_ndr/cli_spoolss.h"
27 #include "nsswitch/libwbclient/wbclient.h"
31 /* when we do not have sufficient input parameters to contact a remote domain
32 * we always fall back to our own realm - Guenther*/
34 static const char *assume_own_realm(struct net_context
*c
)
36 if (!c
->opt_host
&& strequal(lp_workgroup(), c
->opt_target_workgroup
)) {
44 do a cldap netlogon query
46 static int net_ads_cldap_netlogon(struct net_context
*c
, ADS_STRUCT
*ads
)
48 char addr
[INET6_ADDRSTRLEN
];
49 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
51 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
52 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
53 d_fprintf(stderr
, _("CLDAP query failed!\n"));
57 d_printf(_("Information for Domain Controller: %s\n\n"),
60 d_printf(_("Response Type: "));
61 switch (reply
.command
) {
62 case LOGON_SAM_LOGON_USER_UNKNOWN_EX
:
63 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
65 case LOGON_SAM_LOGON_RESPONSE_EX
:
66 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
69 d_printf("0x%x\n", reply
.command
);
73 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply
.domain_uuid
));
77 "\tIs a GC of the forest: %s\n"
78 "\tIs an LDAP server: %s\n"
80 "\tIs running a KDC: %s\n"
81 "\tIs running time services: %s\n"
82 "\tIs the closest DC: %s\n"
84 "\tHas a hardware clock: %s\n"
85 "\tIs a non-domain NC serviced by LDAP server: %s\n"
86 "\tIs NT6 DC that has some secrets: %s\n"
87 "\tIs NT6 DC that has all secrets: %s\n"),
88 (reply
.server_type
& NBT_SERVER_PDC
) ? _("yes") : _("no"),
89 (reply
.server_type
& NBT_SERVER_GC
) ? _("yes") : _("no"),
90 (reply
.server_type
& NBT_SERVER_LDAP
) ? _("yes") : _("no"),
91 (reply
.server_type
& NBT_SERVER_DS
) ? _("yes") : _("no"),
92 (reply
.server_type
& NBT_SERVER_KDC
) ? _("yes") : _("no"),
93 (reply
.server_type
& NBT_SERVER_TIMESERV
) ? _("yes") : _("no"),
94 (reply
.server_type
& NBT_SERVER_CLOSEST
) ? _("yes") : _("no"),
95 (reply
.server_type
& NBT_SERVER_WRITABLE
) ? _("yes") : _("no"),
96 (reply
.server_type
& NBT_SERVER_GOOD_TIMESERV
) ? _("yes") : _("no"),
97 (reply
.server_type
& NBT_SERVER_NDNC
) ? _("yes") : _("no"),
98 (reply
.server_type
& NBT_SERVER_SELECT_SECRET_DOMAIN_6
) ? _("yes") : _("no"),
99 (reply
.server_type
& NBT_SERVER_FULL_SECRET_DOMAIN_6
) ? _("yes") : _("no"));
102 printf(_("Forest:\t\t\t%s\n"), reply
.forest
);
103 printf(_("Domain:\t\t\t%s\n"), reply
.dns_domain
);
104 printf(_("Domain Controller:\t%s\n"), reply
.pdc_dns_name
);
106 printf(_("Pre-Win2k Domain:\t%s\n"), reply
.domain
);
107 printf(_("Pre-Win2k Hostname:\t%s\n"), reply
.pdc_name
);
109 if (*reply
.user_name
) printf(_("User name:\t%s\n"), reply
.user_name
);
111 printf(_("Server Site Name :\t\t%s\n"), reply
.server_site
);
112 printf(_("Client Site Name :\t\t%s\n"), reply
.client_site
);
114 d_printf(_("NT Version: %d\n"), reply
.nt_version
);
115 d_printf(_("LMNT Token: %.2x\n"), reply
.lmnt_token
);
116 d_printf(_("LM20 Token: %.2x\n"), reply
.lm20_token
);
122 this implements the CLDAP based netlogon lookup requests
123 for finding the domain controller of a ADS domain
125 static int net_ads_lookup(struct net_context
*c
, int argc
, const char **argv
)
130 if (c
->display_usage
) {
131 d_printf(_("Usage:\n"),
133 " ",_("Find the ADS DC using CLDAP lookup.\n"));
137 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
138 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
143 if (!ads
->config
.realm
) {
144 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
145 ads
->ldap
.port
= 389;
148 ret
= net_ads_cldap_netlogon(c
, ads
);
155 static int net_ads_info(struct net_context
*c
, int argc
, const char **argv
)
158 char addr
[INET6_ADDRSTRLEN
];
160 if (c
->display_usage
) {
161 d_printf(_("Usage:\n"),
164 _("Display information about an Active Directory "
169 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
170 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
174 if (!ads
|| !ads
->config
.realm
) {
175 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
180 /* Try to set the server's current time since we didn't do a full
181 TCP LDAP session initially */
183 if ( !ADS_ERR_OK(ads_current_time( ads
)) ) {
184 d_fprintf( stderr
, _("Failed to get server's current time!\n"));
187 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
189 d_printf(_("LDAP server: %s\n"), addr
);
190 d_printf(_("LDAP server name: %s\n"), ads
->config
.ldap_server_name
);
191 d_printf(_("Realm: %s\n"), ads
->config
.realm
);
192 d_printf(_("Bind Path: %s\n"), ads
->config
.bind_path
);
193 d_printf(_("LDAP port: %d\n"), ads
->ldap
.port
);
194 d_printf(_("Server time: %s\n"),
195 http_timestring(talloc_tos(), ads
->config
.current_time
));
197 d_printf(_("KDC server: %s\n"), ads
->auth
.kdc_server
);
198 d_printf(_("Server time offset: %d\n"), ads
->auth
.time_offset
);
204 static void use_in_memory_ccache(void) {
205 /* Use in-memory credentials cache so we do not interfere with
206 * existing credentials */
207 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
210 static ADS_STATUS
ads_startup_int(struct net_context
*c
, bool only_own_domain
,
211 uint32 auth_flags
, ADS_STRUCT
**ads_ret
)
213 ADS_STRUCT
*ads
= NULL
;
215 bool need_password
= false;
216 bool second_time
= false;
218 const char *realm
= NULL
;
219 bool tried_closest_dc
= false;
221 /* lp_realm() should be handled by a command line param,
222 However, the join requires that realm be set in smb.conf
223 and compares our realm with the remote server's so this is
224 ok until someone needs more flexibility */
229 if (only_own_domain
) {
232 realm
= assume_own_realm(c
);
235 ads
= ads_init(realm
, c
->opt_target_workgroup
, c
->opt_host
);
237 if (!c
->opt_user_name
) {
238 c
->opt_user_name
= "administrator";
241 if (c
->opt_user_specified
) {
242 need_password
= true;
246 if (!c
->opt_password
&& need_password
&& !c
->opt_machine_pass
) {
247 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
248 if (!c
->opt_password
) {
250 return ADS_ERROR(LDAP_NO_MEMORY
);
254 if (c
->opt_password
) {
255 use_in_memory_ccache();
256 SAFE_FREE(ads
->auth
.password
);
257 ads
->auth
.password
= smb_xstrdup(c
->opt_password
);
260 ads
->auth
.flags
|= auth_flags
;
261 SAFE_FREE(ads
->auth
.user_name
);
262 ads
->auth
.user_name
= smb_xstrdup(c
->opt_user_name
);
265 * If the username is of the form "name@realm",
266 * extract the realm and convert to upper case.
267 * This is only used to establish the connection.
269 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
271 SAFE_FREE(ads
->auth
.realm
);
272 ads
->auth
.realm
= smb_xstrdup(cp
);
273 strupper_m(ads
->auth
.realm
);
276 status
= ads_connect(ads
);
278 if (!ADS_ERR_OK(status
)) {
280 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
281 NT_STATUS_NO_LOGON_SERVERS
)) {
282 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
287 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
288 need_password
= true;
297 /* when contacting our own domain, make sure we use the closest DC.
298 * This is done by reconnecting to ADS because only the first call to
299 * ads_connect will give us our own sitename */
301 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
303 tried_closest_dc
= true; /* avoid loop */
305 if (!ads_closest_dc(ads
)) {
307 namecache_delete(ads
->server
.realm
, 0x1C);
308 namecache_delete(ads
->server
.workgroup
, 0x1C);
321 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
323 return ads_startup_int(c
, only_own_domain
, 0, ads
);
326 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
328 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
332 Check to see if connection can be made via ads.
333 ads_startup() stores the password in opt_password if it needs to so
334 that rpc or rap can use it without re-prompting.
336 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
341 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
345 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
347 status
= ads_connect(ads
);
348 if ( !ADS_ERR_OK(status
) ) {
356 int net_ads_check_our_domain(struct net_context
*c
)
358 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
361 int net_ads_check(struct net_context
*c
)
363 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
367 determine the netbios workgroup name for a domain
369 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
372 char addr
[INET6_ADDRSTRLEN
];
373 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
375 if (c
->display_usage
) {
376 d_printf(_("Usage:\n"),
377 "net ads workgroup\n"
378 " ",_("Print the workgroup name\n"));
382 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
383 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
387 if (!ads
->config
.realm
) {
388 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
389 ads
->ldap
.port
= 389;
392 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
393 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
394 d_fprintf(stderr
, _("CLDAP query failed!\n"));
399 d_printf(_("Workgroup: %s\n"), reply
.domain
);
408 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
410 char **disp_fields
= (char **) data_area
;
412 if (!field
) { /* must be end of record */
413 if (disp_fields
[0]) {
414 if (!strchr_m(disp_fields
[0], '$')) {
416 d_printf("%-21.21s %s\n",
417 disp_fields
[0], disp_fields
[1]);
419 d_printf("%s\n", disp_fields
[0]);
422 SAFE_FREE(disp_fields
[0]);
423 SAFE_FREE(disp_fields
[1]);
426 if (!values
) /* must be new field, indicate string field */
428 if (StrCaseCmp(field
, "sAMAccountName") == 0) {
429 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
431 if (StrCaseCmp(field
, "description") == 0)
432 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
436 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
438 return net_user_usage(c
, argc
, argv
);
441 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
446 LDAPMessage
*res
=NULL
;
450 if (argc
< 1 || c
->display_usage
)
451 return net_ads_user_usage(c
, argc
, argv
);
453 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
457 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
459 if (!ADS_ERR_OK(status
)) {
460 d_fprintf(stderr
, _("ads_user_add: %s\n"), ads_errstr(status
));
464 if (ads_count_replies(ads
, res
)) {
465 d_fprintf(stderr
, _("ads_user_add: User %s already exists\n"),
470 if (c
->opt_container
) {
471 ou_str
= SMB_STRDUP(c
->opt_container
);
473 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
476 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
478 if (!ADS_ERR_OK(status
)) {
479 d_fprintf(stderr
, _("Could not add user %s: %s\n"), argv
[0],
484 /* if no password is to be set, we're done */
486 d_printf(_("User %s added\n"), argv
[0]);
491 /* try setting the password */
492 if (asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
) == -1) {
495 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
496 ads
->auth
.time_offset
);
498 if (ADS_ERR_OK(status
)) {
499 d_printf(_("User %s added\n"), argv
[0]);
504 /* password didn't set, delete account */
505 d_fprintf(stderr
, _("Could not add user %s. "
506 "Error setting password %s\n"),
507 argv
[0], ads_errstr(status
));
508 ads_msgfree(ads
, res
);
509 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
510 if (ADS_ERR_OK(status
)) {
511 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
512 ads_del_dn(ads
, userdn
);
518 ads_msgfree(ads
, res
);
524 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
526 ADS_STRUCT
*ads
= NULL
;
528 LDAPMessage
*res
= NULL
;
532 const char *attrs
[] = {"memberOf", "primaryGroupID", NULL
};
533 char *searchstring
=NULL
;
537 DOM_SID primary_group_sid
;
539 enum SID_NAME_USE type
;
541 if (argc
< 1 || c
->display_usage
) {
542 return net_ads_user_usage(c
, argc
, argv
);
545 frame
= talloc_new(talloc_tos());
550 escaped_user
= escape_ldap_string(frame
, argv
[0]);
553 _("ads_user_info: failed to escape user %s\n"),
558 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
563 if (asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
) == -1) {
567 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
568 SAFE_FREE(searchstring
);
570 if (!ADS_ERR_OK(rc
)) {
571 d_fprintf(stderr
, _("ads_search: %s\n"), ads_errstr(rc
));
576 if (!ads_pull_uint32(ads
, res
, "primaryGroupID", &group_rid
)) {
577 d_fprintf(stderr
, _("ads_pull_uint32 failed\n"));
582 rc
= ads_domain_sid(ads
, &primary_group_sid
);
583 if (!ADS_ERR_OK(rc
)) {
584 d_fprintf(stderr
, _("ads_domain_sid: %s\n"), ads_errstr(rc
));
589 sid_append_rid(&primary_group_sid
, group_rid
);
591 wbc_status
= wbcLookupSid((struct wbcDomainSid
*)&primary_group_sid
,
592 NULL
, /* don't look up domain */
594 (enum wbcSidType
*) &type
);
595 if (!WBC_ERROR_IS_OK(wbc_status
)) {
596 d_fprintf(stderr
, "wbcLookupSid: %s\n",
597 wbcErrorString(wbc_status
));
602 d_printf("%s\n", primary_group
);
604 wbcFreeMemory(primary_group
);
606 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
607 (LDAPMessage
*)res
, "memberOf");
612 for (i
=0;grouplist
[i
];i
++) {
613 groupname
= ldap_explode_dn(grouplist
[i
], 1);
614 d_printf("%s\n", groupname
[0]);
615 ldap_value_free(groupname
);
617 ldap_value_free(grouplist
);
621 if (res
) ads_msgfree(ads
, res
);
622 if (ads
) ads_destroy(&ads
);
627 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
631 LDAPMessage
*res
= NULL
;
635 return net_ads_user_usage(c
, argc
, argv
);
638 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
642 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
643 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
644 d_printf(_("User %s does not exist.\n"), argv
[0]);
645 ads_msgfree(ads
, res
);
649 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
650 ads_msgfree(ads
, res
);
651 rc
= ads_del_dn(ads
, userdn
);
653 if (ADS_ERR_OK(rc
)) {
654 d_printf(_("User %s deleted\n"), argv
[0]);
658 d_fprintf(stderr
, _("Error deleting user %s: %s\n"), argv
[0],
664 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
666 struct functable func
[] = {
671 N_("Add an AD user"),
672 N_("net ads user add\n"
679 N_("Display information about an AD user"),
680 N_("net ads user info\n"
681 " Display information about an AD user")
687 N_("Delete an AD user"),
688 N_("net ads user delete\n"
689 " Delete an AD user")
691 {NULL
, NULL
, 0, NULL
, NULL
}
695 const char *shortattrs
[] = {"sAMAccountName", NULL
};
696 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
697 char *disp_fields
[2] = {NULL
, NULL
};
700 if (c
->display_usage
) {
701 d_printf(_("Usage:\n"),
703 " ",_("List AD users\n"));
704 net_display_usage_from_functable(func
);
708 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
712 if (c
->opt_long_list_entries
)
713 d_printf(_("\nUser name Comment"
714 "\n-----------------------------\n"));
716 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
718 "(objectCategory=user)",
719 c
->opt_long_list_entries
? longattrs
:
720 shortattrs
, usergrp_display
,
723 return ADS_ERR_OK(rc
) ? 0 : -1;
726 return net_run_function(c
, argc
, argv
, "net ads user", func
);
729 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
731 return net_group_usage(c
, argc
, argv
);
734 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
738 LDAPMessage
*res
=NULL
;
742 if (argc
< 1 || c
->display_usage
) {
743 return net_ads_group_usage(c
, argc
, argv
);
746 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
750 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
752 if (!ADS_ERR_OK(status
)) {
753 d_fprintf(stderr
, _("ads_group_add: %s\n"), ads_errstr(status
));
757 if (ads_count_replies(ads
, res
)) {
758 d_fprintf(stderr
, _("ads_group_add: Group %s already exists\n"), argv
[0]);
762 if (c
->opt_container
) {
763 ou_str
= SMB_STRDUP(c
->opt_container
);
765 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
768 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
770 if (ADS_ERR_OK(status
)) {
771 d_printf(_("Group %s added\n"), argv
[0]);
774 d_fprintf(stderr
, _("Could not add group %s: %s\n"), argv
[0],
780 ads_msgfree(ads
, res
);
786 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
790 LDAPMessage
*res
= NULL
;
793 if (argc
< 1 || c
->display_usage
) {
794 return net_ads_group_usage(c
, argc
, argv
);
797 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
801 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
802 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
803 d_printf(_("Group %s does not exist.\n"), argv
[0]);
804 ads_msgfree(ads
, res
);
808 groupdn
= ads_get_dn(ads
, talloc_tos(), res
);
809 ads_msgfree(ads
, res
);
810 rc
= ads_del_dn(ads
, groupdn
);
811 TALLOC_FREE(groupdn
);
812 if (ADS_ERR_OK(rc
)) {
813 d_printf(_("Group %s deleted\n"), argv
[0]);
817 d_fprintf(stderr
, _("Error deleting group %s: %s\n"), argv
[0],
823 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
825 struct functable func
[] = {
830 N_("Add an AD group"),
831 N_("net ads group add\n"
838 N_("Delete an AD group"),
839 N_("net ads group delete\n"
840 " Delete an AD group")
842 {NULL
, NULL
, 0, NULL
, NULL
}
846 const char *shortattrs
[] = {"sAMAccountName", NULL
};
847 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
848 char *disp_fields
[2] = {NULL
, NULL
};
851 if (c
->display_usage
) {
852 d_printf(_("Usage:\n"),
854 " ", _("List AD groups\n"));
855 net_display_usage_from_functable(func
);
859 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
863 if (c
->opt_long_list_entries
)
864 d_printf(_("\nGroup name Comment"
865 "\n-----------------------------\n"));
866 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
868 "(objectCategory=group)",
869 c
->opt_long_list_entries
? longattrs
:
870 shortattrs
, usergrp_display
,
874 return ADS_ERR_OK(rc
) ? 0 : -1;
876 return net_run_function(c
, argc
, argv
, "net ads group", func
);
879 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
885 if (c
->display_usage
) {
886 d_printf(_("Usage:\n"),
888 " ",_("Display machine account details\n"));
892 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
896 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
897 if (!ADS_ERR_OK(rc
)) {
898 d_fprintf(stderr
, _("ads_find_machine_acct: %s\n"), ads_errstr(rc
));
903 if (ads_count_replies(ads
, res
) == 0) {
904 d_fprintf(stderr
, _("No machine account for '%s' found\n"), global_myname());
914 /*******************************************************************
915 Leave an AD domain. Windows XP disables the machine account.
916 We'll try the same. The old code would do an LDAP delete.
917 That only worked using the machine creds because added the machine
918 with full control to the computer object's ACL.
919 *******************************************************************/
921 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
924 struct libnet_UnjoinCtx
*r
= NULL
;
927 if (c
->display_usage
) {
928 d_printf(_("Usage:\n"),
930 " ", _("Leave an AD domain\n"));
935 d_fprintf(stderr
, _("No realm set, are we joined ?\n"));
939 if (!(ctx
= talloc_init("net_ads_leave"))) {
940 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
944 if (!c
->opt_kerberos
) {
945 use_in_memory_ccache();
948 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
949 if (!W_ERROR_IS_OK(werr
)) {
950 d_fprintf(stderr
, _("Could not initialise unjoin context.\n"));
955 r
->in
.use_kerberos
= c
->opt_kerberos
;
956 r
->in
.dc_name
= c
->opt_host
;
957 r
->in
.domain_name
= lp_realm();
958 r
->in
.admin_account
= c
->opt_user_name
;
959 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
960 r
->in
.modify_config
= lp_config_backend_is_registry();
962 /* Try to delete it, but if that fails, disable it. The
963 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
964 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
965 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
966 r
->in
.delete_machine_account
= true;
968 werr
= libnet_Unjoin(ctx
, r
);
969 if (!W_ERROR_IS_OK(werr
)) {
970 d_printf(_("Failed to leave domain: %s\n"),
971 r
->out
.error_string
? r
->out
.error_string
:
972 get_friendly_werror_msg(werr
));
976 if (r
->out
.deleted_machine_account
) {
977 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
978 r
->in
.machine_name
, r
->out
.dns_domain_name
);
982 /* We couldn't delete it - see if the disable succeeded. */
983 if (r
->out
.disabled_machine_account
) {
984 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
985 r
->in
.machine_name
, r
->out
.dns_domain_name
);
990 /* Based on what we requseted, we shouldn't get here, but if
991 we did, it means the secrets were removed, and therefore
992 we have left the domain */
993 d_fprintf(stderr
, _("Machine '%s' Left domain '%s'\n"),
994 r
->in
.machine_name
, r
->out
.dns_domain_name
);
1000 if (W_ERROR_IS_OK(werr
)) {
1007 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
1009 ADS_STRUCT
*ads
= NULL
;
1012 struct sockaddr_storage dcip
;
1014 if (!secrets_init()) {
1015 DEBUG(1,("Failed to initialise secrets database\n"));
1016 return NT_STATUS_ACCESS_DENIED
;
1019 net_use_krb_machine_account(c
);
1021 get_dc_name(lp_workgroup(), lp_realm(), dc_name
, &dcip
);
1023 status
= ads_startup(c
, true, &ads
);
1024 if (!ADS_ERR_OK(status
)) {
1025 return ads_ntstatus(status
);
1029 return NT_STATUS_OK
;
1033 check that an existing join is OK
1035 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
1038 use_in_memory_ccache();
1040 if (c
->display_usage
) {
1041 d_printf(_("Usage:\n"),
1042 "net ads testjoin\n"
1043 " ", _("Test if the existing join is ok\n"));
1047 /* Display success or failure */
1048 status
= net_ads_join_ok(c
);
1049 if (!NT_STATUS_IS_OK(status
)) {
1050 fprintf(stderr
, _("Join to domain is not valid: %s\n"),
1051 get_friendly_nt_error_msg(status
));
1055 printf(_("Join is OK\n"));
1059 /*******************************************************************
1060 Simple configu checks before beginning the join
1061 ********************************************************************/
1063 static WERROR
check_ads_config( void )
1065 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
1066 d_printf(_("Host is not configured as a member server.\n"));
1067 return WERR_INVALID_DOMAIN_ROLE
;
1070 if (strlen(global_myname()) > 15) {
1071 d_printf(_("Our netbios name can be at most 15 chars long, "
1072 "\"%s\" is %u chars long\n"), global_myname(),
1073 (unsigned int)strlen(global_myname()));
1074 return WERR_INVALID_COMPUTERNAME
;
1077 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1078 d_fprintf(stderr
, _("realm must be set in in %s for ADS "
1079 "join to succeed.\n"), get_dyn_CONFIGFILE());
1080 return WERR_INVALID_PARAM
;
1086 /*******************************************************************
1087 Send a DNS update request
1088 *******************************************************************/
1090 #if defined(WITH_DNS_UPDATES)
1092 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
1093 const char *pszDomainName
, const char *pszHostName
,
1094 const struct sockaddr_storage
*sslist
,
1097 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1098 const char *machine_name
,
1099 const struct sockaddr_storage
*addrs
,
1102 struct dns_rr_ns
*nameservers
= NULL
;
1104 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1107 const char *dnsdomain
= NULL
;
1108 char *root_domain
= NULL
;
1110 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1111 d_printf(_("No DNS domain configured for %s. "
1112 "Unable to perform DNS Update.\n"), machine_name
);
1113 status
= NT_STATUS_INVALID_PARAMETER
;
1118 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
1119 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1120 /* Child domains often do not have NS records. Look
1121 for the NS record for the forest root domain
1122 (rootDomainNamingContext in therootDSE) */
1124 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1125 LDAPMessage
*msg
= NULL
;
1127 ADS_STATUS ads_status
;
1129 if ( !ads
->ldap
.ld
) {
1130 ads_status
= ads_connect( ads
);
1131 if ( !ADS_ERR_OK(ads_status
) ) {
1132 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1137 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1138 "(objectclass=*)", rootname_attrs
, &msg
);
1139 if (!ADS_ERR_OK(ads_status
)) {
1143 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1145 ads_msgfree( ads
, msg
);
1149 root_domain
= ads_build_domain( root_dn
);
1152 ads_msgfree( ads
, msg
);
1154 /* try again for NS servers */
1156 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1158 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1159 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1160 "realm\n", ads
->config
.realm
));
1164 dnsdomain
= root_domain
;
1168 /* Now perform the dns update - we'll try non-secure and if we fail,
1169 we'll follow it up with a secure update */
1171 fstrcpy( dns_server
, nameservers
[0].hostname
);
1173 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1174 if (!ERR_DNS_IS_OK(dns_err
)) {
1175 status
= NT_STATUS_UNSUCCESSFUL
;
1180 SAFE_FREE( root_domain
);
1185 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
)
1188 struct sockaddr_storage
*iplist
= NULL
;
1189 fstring machine_name
;
1192 name_to_fqdn( machine_name
, global_myname() );
1193 strlower_m( machine_name
);
1195 /* Get our ip address (not the 127.0.0.x address but a real ip
1198 num_addrs
= get_my_ip_address( &iplist
);
1199 if ( num_addrs
<= 0 ) {
1200 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1202 return NT_STATUS_INVALID_PARAMETER
;
1205 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1207 SAFE_FREE( iplist
);
1213 /*******************************************************************
1214 ********************************************************************/
1216 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1218 d_printf(_("net ads join [options]\n"
1219 "Valid options:\n"));
1220 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1221 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1222 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1223 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1224 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1225 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1226 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1227 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1228 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1229 " NB: osName and osVer must be specified together for either to take effect.\n"
1230 " Also, the operatingSystemService attribute is also set when along with\n"
1231 " the two other attributes.\n"));
1236 /*******************************************************************
1237 ********************************************************************/
1239 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1241 TALLOC_CTX
*ctx
= NULL
;
1242 struct libnet_JoinCtx
*r
= NULL
;
1243 const char *domain
= lp_realm();
1244 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1245 bool createupn
= false;
1246 const char *machineupn
= NULL
;
1247 const char *create_in_ou
= NULL
;
1249 const char *os_name
= NULL
;
1250 const char *os_version
= NULL
;
1251 bool modify_config
= lp_config_backend_is_registry();
1253 if (c
->display_usage
)
1254 return net_ads_join_usage(c
, argc
, argv
);
1256 if (!modify_config
) {
1258 werr
= check_ads_config();
1259 if (!W_ERROR_IS_OK(werr
)) {
1260 d_fprintf(stderr
, _("Invalid configuration. Exiting....\n"));
1265 if (!(ctx
= talloc_init("net_ads_join"))) {
1266 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
1271 if (!c
->opt_kerberos
) {
1272 use_in_memory_ccache();
1275 werr
= libnet_init_JoinCtx(ctx
, &r
);
1276 if (!W_ERROR_IS_OK(werr
)) {
1280 /* process additional command line args */
1282 for ( i
=0; i
<argc
; i
++ ) {
1283 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1285 machineupn
= get_string_param(argv
[i
]);
1287 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1288 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1289 d_fprintf(stderr
, _("Please supply a valid OU path.\n"));
1290 werr
= WERR_INVALID_PARAM
;
1294 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1295 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1296 d_fprintf(stderr
, _("Please supply a operating system name.\n"));
1297 werr
= WERR_INVALID_PARAM
;
1301 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1302 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1303 d_fprintf(stderr
, _("Please supply a valid operating system version.\n"));
1304 werr
= WERR_INVALID_PARAM
;
1314 d_fprintf(stderr
, _("Please supply a valid domain name\n"));
1315 werr
= WERR_INVALID_PARAM
;
1319 /* Do the domain join here */
1321 r
->in
.domain_name
= domain
;
1322 r
->in
.create_upn
= createupn
;
1323 r
->in
.upn
= machineupn
;
1324 r
->in
.account_ou
= create_in_ou
;
1325 r
->in
.os_name
= os_name
;
1326 r
->in
.os_version
= os_version
;
1327 r
->in
.dc_name
= c
->opt_host
;
1328 r
->in
.admin_account
= c
->opt_user_name
;
1329 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1331 r
->in
.use_kerberos
= c
->opt_kerberos
;
1332 r
->in
.modify_config
= modify_config
;
1333 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1334 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1335 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1337 werr
= libnet_Join(ctx
, r
);
1338 if (!W_ERROR_IS_OK(werr
)) {
1342 /* Check the short name of the domain */
1344 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1345 d_printf(_("The workgroup in %s does not match the short\n"
1346 "domain name obtained from the server.\n"
1347 "Using the name [%s] from the server.\n"
1348 "You should set \"workgroup = %s\" in %s.\n"),
1349 get_dyn_CONFIGFILE(), r
->out
.netbios_domain_name
,
1350 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1353 d_printf(_("Using short domain name -- %s\n"), r
->out
.netbios_domain_name
);
1355 if (r
->out
.dns_domain_name
) {
1356 d_printf(_("Joined '%s' to realm '%s'\n"), r
->in
.machine_name
,
1357 r
->out
.dns_domain_name
);
1359 d_printf(_("Joined '%s' to domain '%s'\n"), r
->in
.machine_name
,
1360 r
->out
.netbios_domain_name
);
1363 #if defined(WITH_DNS_UPDATES)
1364 if (r
->out
.domain_is_ad
) {
1365 /* We enter this block with user creds */
1366 ADS_STRUCT
*ads_dns
= NULL
;
1368 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1369 /* kinit with the machine password */
1371 use_in_memory_ccache();
1372 if (asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname()) == -1) {
1375 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1376 r
->out
.netbios_domain_name
, NULL
, NULL
);
1377 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1378 strupper_m(ads_dns
->auth
.realm
);
1379 ads_kinit_password( ads_dns
);
1382 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns( ctx
, ads_dns
)) ) {
1383 d_fprintf( stderr
, _("DNS update failed!\n") );
1386 /* exit from this block using machine creds */
1387 ads_destroy(&ads_dns
);
1396 /* issue an overall failure message at the end. */
1397 d_printf(_("Failed to join domain: %s\n"),
1398 r
&& r
->out
.error_string
? r
->out
.error_string
:
1399 get_friendly_werror_msg(werr
));
1405 /*******************************************************************
1406 ********************************************************************/
1408 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1410 #if defined(WITH_DNS_UPDATES)
1416 talloc_enable_leak_report();
1419 if (argc
> 0 || c
->display_usage
) {
1420 d_printf(_("Usage:\n"),
1421 "net ads dns register\n"
1422 " ", _("Register hostname with DNS\n"));
1426 if (!(ctx
= talloc_init("net_ads_dns"))) {
1427 d_fprintf(stderr
, _("Could not initialise talloc context\n"));
1431 status
= ads_startup(c
, true, &ads
);
1432 if ( !ADS_ERR_OK(status
) ) {
1433 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1438 if ( !NT_STATUS_IS_OK(net_update_dns(ctx
, ads
)) ) {
1439 d_fprintf( stderr
, _("DNS update failed!\n") );
1440 ads_destroy( &ads
);
1445 d_fprintf( stderr
, _("Successfully registered hostname with DNS\n") );
1453 _("DNS update support not enabled at compile time!\n"));
1458 #if defined(WITH_DNS_UPDATES)
1459 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1462 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1464 #if defined(WITH_DNS_UPDATES)
1468 talloc_enable_leak_report();
1471 if (argc
!= 2 || c
->display_usage
) {
1472 d_printf(_("Usage:\n"),
1473 _("net ads dns gethostbyname <server> <name>\n"),
1474 _(" Look up hostname from the AD\n"
1475 " server\tName server to use\n"
1476 " name\tName to look up\n"));
1480 err
= do_gethostbyname(argv
[0], argv
[1]);
1482 d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err
));
1487 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1489 struct functable func
[] = {
1492 net_ads_dns_register
,
1494 N_("Add host dns entry to AD"),
1495 N_("net ads dns register\n"
1496 " Add host dns entry to AD")
1500 net_ads_dns_gethostbyname
,
1503 N_("net ads dns gethostbyname\n"
1506 {NULL
, NULL
, 0, NULL
, NULL
}
1509 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1512 /*******************************************************************
1513 ********************************************************************/
1515 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1518 "\nnet ads printer search <printer>"
1519 "\n\tsearch for a printer in the directory\n"
1520 "\nnet ads printer info <printer> <server>"
1521 "\n\tlookup info in directory for printer on server"
1522 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1523 "\nnet ads printer publish <printername>"
1524 "\n\tpublish printer in directory"
1525 "\n\t(note: printer name is required)\n"
1526 "\nnet ads printer remove <printername>"
1527 "\n\tremove printer from directory"
1528 "\n\t(note: printer name is required)\n"));
1532 /*******************************************************************
1533 ********************************************************************/
1535 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1539 LDAPMessage
*res
= NULL
;
1541 if (c
->display_usage
) {
1542 d_printf(_("Usage:\n"),
1543 "net ads printer search\n"
1544 " ", _("List printers in the AD\n"));
1548 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1552 rc
= ads_find_printers(ads
, &res
);
1554 if (!ADS_ERR_OK(rc
)) {
1555 d_fprintf(stderr
, _("ads_find_printer: %s\n"), ads_errstr(rc
));
1556 ads_msgfree(ads
, res
);
1561 if (ads_count_replies(ads
, res
) == 0) {
1562 d_fprintf(stderr
, _("No results found\n"));
1563 ads_msgfree(ads
, res
);
1569 ads_msgfree(ads
, res
);
1574 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1578 const char *servername
, *printername
;
1579 LDAPMessage
*res
= NULL
;
1581 if (c
->display_usage
) {
1582 d_printf(_("Usage:\n"),
1583 _("net ads printer info [printername [servername]]\n"
1584 " Display printer info from AD\n"
1585 " printername\tPrinter name or wildcard\n"
1586 " servername\tName of the print server\n"));
1590 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1595 printername
= argv
[0];
1601 servername
= argv
[1];
1603 servername
= global_myname();
1606 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1608 if (!ADS_ERR_OK(rc
)) {
1609 d_fprintf(stderr
, _("Server '%s' not found: %s\n"),
1610 servername
, ads_errstr(rc
));
1611 ads_msgfree(ads
, res
);
1616 if (ads_count_replies(ads
, res
) == 0) {
1617 d_fprintf(stderr
, _("Printer '%s' not found\n"), printername
);
1618 ads_msgfree(ads
, res
);
1624 ads_msgfree(ads
, res
);
1630 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1634 const char *servername
, *printername
;
1635 struct cli_state
*cli
= NULL
;
1636 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1637 struct sockaddr_storage server_ss
;
1639 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1640 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1641 char *prt_dn
, *srv_dn
, **srv_cn
;
1642 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1643 LDAPMessage
*res
= NULL
;
1645 if (argc
< 1 || c
->display_usage
) {
1646 d_printf(_("Usage:\n"),
1647 _("net ads printer publish <printername> [servername]\n"
1648 " Publish printer in AD\n"
1649 " printername\tName of the printer\n"
1650 " servername\tName of the print server\n"));
1651 talloc_destroy(mem_ctx
);
1655 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1656 talloc_destroy(mem_ctx
);
1660 printername
= argv
[0];
1663 servername
= argv
[1];
1665 servername
= global_myname();
1668 /* Get printer data from SPOOLSS */
1670 resolve_name(servername
, &server_ss
, 0x20, false);
1672 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1675 c
->opt_user_name
, c
->opt_workgroup
,
1676 c
->opt_password
? c
->opt_password
: "",
1677 CLI_FULL_CONNECTION_USE_KERBEROS
,
1680 if (NT_STATUS_IS_ERR(nt_status
)) {
1681 d_fprintf(stderr
, _("Unable to open a connnection to %s to "
1682 "obtain data for %s\n"),
1683 servername
, printername
);
1685 talloc_destroy(mem_ctx
);
1689 /* Publish on AD server */
1691 ads_find_machine_acct(ads
, &res
, servername
);
1693 if (ads_count_replies(ads
, res
) == 0) {
1694 d_fprintf(stderr
, _("Could not find machine account for server "
1698 talloc_destroy(mem_ctx
);
1702 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1703 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1705 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1706 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1707 if (!srv_cn_escaped
|| !printername_escaped
) {
1708 SAFE_FREE(srv_cn_escaped
);
1709 SAFE_FREE(printername_escaped
);
1710 d_fprintf(stderr
, _("Internal error, out of memory!"));
1712 talloc_destroy(mem_ctx
);
1716 if (asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
) == -1) {
1717 SAFE_FREE(srv_cn_escaped
);
1718 SAFE_FREE(printername_escaped
);
1719 d_fprintf(stderr
, _("Internal error, out of memory!"));
1721 talloc_destroy(mem_ctx
);
1725 SAFE_FREE(srv_cn_escaped
);
1726 SAFE_FREE(printername_escaped
);
1728 nt_status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_spoolss
.syntax_id
, &pipe_hnd
);
1729 if (!NT_STATUS_IS_OK(nt_status
)) {
1730 d_fprintf(stderr
, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1734 talloc_destroy(mem_ctx
);
1738 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1742 talloc_destroy(mem_ctx
);
1746 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1747 if (!ADS_ERR_OK(rc
)) {
1748 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1751 talloc_destroy(mem_ctx
);
1755 d_printf("published printer\n");
1758 talloc_destroy(mem_ctx
);
1763 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1767 const char *servername
;
1769 LDAPMessage
*res
= NULL
;
1771 if (argc
< 1 || c
->display_usage
) {
1772 d_printf(_("Usage:\n"),
1773 _("net ads printer remove <printername> [servername]\n"
1774 " Remove a printer from the AD\n"
1775 " printername\tName of the printer\n"
1776 " servername\tName of the print server\n"));
1780 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1785 servername
= argv
[1];
1787 servername
= global_myname();
1790 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1792 if (!ADS_ERR_OK(rc
)) {
1793 d_fprintf(stderr
, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc
));
1794 ads_msgfree(ads
, res
);
1799 if (ads_count_replies(ads
, res
) == 0) {
1800 d_fprintf(stderr
, _("Printer '%s' not found\n"), argv
[1]);
1801 ads_msgfree(ads
, res
);
1806 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
1807 ads_msgfree(ads
, res
);
1808 rc
= ads_del_dn(ads
, prt_dn
);
1809 TALLOC_FREE(prt_dn
);
1811 if (!ADS_ERR_OK(rc
)) {
1812 d_fprintf(stderr
, _("ads_del_dn: %s\n"), ads_errstr(rc
));
1821 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
1823 struct functable func
[] = {
1826 net_ads_printer_search
,
1828 N_("Search for a printer"),
1829 N_("net ads printer search\n"
1830 " Search for a printer")
1834 net_ads_printer_info
,
1836 N_("Display printer information"),
1837 N_("net ads printer info\n"
1838 " Display printer information")
1842 net_ads_printer_publish
,
1844 N_("Publish a printer"),
1845 N_("net ads printer publish\n"
1846 " Publish a printer")
1850 net_ads_printer_remove
,
1852 N_("Delete a printer"),
1853 N_("net ads printer remove\n"
1854 " Delete a printer")
1856 {NULL
, NULL
, 0, NULL
, NULL
}
1859 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
1863 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
1866 const char *auth_principal
= c
->opt_user_name
;
1867 const char *auth_password
= c
->opt_password
;
1869 char *new_password
= NULL
;
1874 if (c
->display_usage
) {
1875 d_printf(_("Usage:\n"),
1876 _("net ads password <username>\n"
1877 " Change password for user\n"
1878 " username\tName of user to change password for\n"));
1882 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
1883 d_fprintf(stderr
, _("You must supply an administrator "
1884 "username/password\n"));
1889 d_fprintf(stderr
, _("ERROR: You must say which username to "
1890 "change password for\n"));
1895 if (!strchr_m(user
, '@')) {
1896 if (asprintf(&chr
, "%s@%s", argv
[0], lp_realm()) == -1) {
1902 use_in_memory_ccache();
1903 chr
= strchr_m(auth_principal
, '@');
1910 /* use the realm so we can eventually change passwords for users
1911 in realms other than default */
1912 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
1916 /* we don't actually need a full connect, but it's the easy way to
1917 fill in the KDC's addresss */
1920 if (!ads
->config
.realm
) {
1921 d_fprintf(stderr
, _("Didn't find the kerberos server!\n"));
1927 new_password
= (char *)argv
[1];
1929 if (asprintf(&prompt
, _("Enter new password for %s:"), user
) == -1) {
1932 new_password
= getpass(prompt
);
1936 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
1937 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
1938 if (!ADS_ERR_OK(ret
)) {
1939 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
1944 d_printf(_("Password change for %s completed.\n"), user
);
1950 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
1953 char *host_principal
;
1957 if (c
->display_usage
) {
1958 d_printf(_("Usage:\n"),
1959 "net ads changetrustpw\n"
1960 " ", _("Change the machine account's trust password\n"));
1964 if (!secrets_init()) {
1965 DEBUG(1,("Failed to initialise secrets database\n"));
1969 net_use_krb_machine_account(c
);
1971 use_in_memory_ccache();
1973 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1977 fstrcpy(my_name
, global_myname());
1978 strlower_m(my_name
);
1979 if (asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
) == -1) {
1983 d_printf(_("Changing password for principal: %s\n"), host_principal
);
1985 ret
= ads_change_trust_account_password(ads
, host_principal
);
1987 if (!ADS_ERR_OK(ret
)) {
1988 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
1990 SAFE_FREE(host_principal
);
1994 d_printf(_("Password change for principal %s succeeded.\n"), host_principal
);
1996 if (USE_SYSTEM_KEYTAB
) {
1997 d_printf(_("Attempting to update system keytab with new password.\n"));
1998 if (ads_keytab_create_default(ads
)) {
1999 d_printf(_("Failed to update system keytab.\n"));
2004 SAFE_FREE(host_principal
);
2010 help for net ads search
2012 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
2015 "\nnet ads search <expression> <attributes...>\n"
2016 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2017 "The expression is a standard LDAP search expression, and the\n"
2018 "attributes are a list of LDAP fields to show in the results.\n\n"
2019 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2021 net_common_flags_usage(c
, argc
, argv
);
2027 general ADS search function. Useful in diagnosing problems in ADS
2029 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
2033 const char *ldap_exp
;
2035 LDAPMessage
*res
= NULL
;
2037 if (argc
< 1 || c
->display_usage
) {
2038 return net_ads_search_usage(c
, argc
, argv
);
2041 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2048 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
2050 ldap_exp
, attrs
, &res
);
2051 if (!ADS_ERR_OK(rc
)) {
2052 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2057 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2059 /* dump the results */
2062 ads_msgfree(ads
, res
);
2070 help for net ads search
2072 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
2075 "\nnet ads dn <dn> <attributes...>\n"
2076 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2077 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2078 "to show in the results\n\n"
2079 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2080 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2082 net_common_flags_usage(c
, argc
, argv
);
2088 general ADS search function. Useful in diagnosing problems in ADS
2090 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
2096 LDAPMessage
*res
= NULL
;
2098 if (argc
< 1 || c
->display_usage
) {
2099 return net_ads_dn_usage(c
, argc
, argv
);
2102 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2109 rc
= ads_do_search_all(ads
, dn
,
2111 "(objectclass=*)", attrs
, &res
);
2112 if (!ADS_ERR_OK(rc
)) {
2113 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2118 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2120 /* dump the results */
2123 ads_msgfree(ads
, res
);
2130 help for net ads sid search
2132 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2135 "\nnet ads sid <sid> <attributes...>\n"
2136 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2137 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2138 "to show in the results\n\n"
2139 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2141 net_common_flags_usage(c
, argc
, argv
);
2147 general ADS search function. Useful in diagnosing problems in ADS
2149 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2153 const char *sid_string
;
2155 LDAPMessage
*res
= NULL
;
2158 if (argc
< 1 || c
->display_usage
) {
2159 return net_ads_sid_usage(c
, argc
, argv
);
2162 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2166 sid_string
= argv
[0];
2169 if (!string_to_sid(&sid
, sid_string
)) {
2170 d_fprintf(stderr
, _("could not convert sid\n"));
2175 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2176 if (!ADS_ERR_OK(rc
)) {
2177 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2182 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2184 /* dump the results */
2187 ads_msgfree(ads
, res
);
2193 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2198 if (c
->display_usage
) {
2199 d_printf(_("Usage:\n"),
2200 "net ads keytab flush\n"
2201 " ", _("Delete the whole keytab\n"));
2205 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2208 ret
= ads_keytab_flush(ads
);
2213 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2219 if (c
->display_usage
) {
2220 d_printf(_("Usage:\n"),
2221 _("net ads keytab add <principal> [principal ...]\n"
2222 " Add principals to local keytab\n"
2223 " principal\tKerberos principal to add to "
2228 d_printf(_("Processing principals to add...\n"));
2229 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2232 for (i
= 0; i
< argc
; i
++) {
2233 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2239 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2244 if (c
->display_usage
) {
2245 d_printf(_("Usage:\n"),
2246 "net ads keytab create\n"
2247 " ", _("Create new default keytab\n"));
2251 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2254 ret
= ads_keytab_create_default(ads
);
2259 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2261 const char *keytab
= NULL
;
2263 if (c
->display_usage
) {
2264 d_printf(_("Usage:\n"),
2265 _("net ads keytab list [keytab]\n"
2266 " List a local keytab\n"
2267 " keytab\tKeytab to list\n"));
2275 return ads_keytab_list(keytab
);
2279 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2281 struct functable func
[] = {
2286 N_("Add a service principal"),
2287 N_("net ads keytab add\n"
2288 " Add a service principal")
2292 net_ads_keytab_create
,
2294 N_("Create a fresh keytab"),
2295 N_("net ads keytab create\n"
2296 " Create a fresh keytab")
2300 net_ads_keytab_flush
,
2302 N_("Remove all keytab entries"),
2303 N_("net ads keytab flush\n"
2304 " Remove all keytab entries")
2308 net_ads_keytab_list
,
2310 N_("List a keytab"),
2311 N_("net ads keytab list\n"
2314 {NULL
, NULL
, 0, NULL
, NULL
}
2317 if (!USE_KERBEROS_KEYTAB
) {
2318 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2319 "keytab method to use keytab functions.\n"));
2322 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2325 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2329 if (c
->display_usage
) {
2330 d_printf(_("Usage:\n"),
2331 "net ads kerberos renew\n"
2332 " ", _("Renew TGT from existing credential cache\n"));
2336 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2338 d_printf(_("failed to renew kerberos ticket: %s\n"),
2339 error_message(ret
));
2344 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2346 struct PAC_DATA
*pac
= NULL
;
2347 struct PAC_LOGON_INFO
*info
= NULL
;
2348 TALLOC_CTX
*mem_ctx
= NULL
;
2351 const char *impersonate_princ_s
= NULL
;
2353 if (c
->display_usage
) {
2354 d_printf(_("Usage:\n"),
2355 "net ads kerberos pac\n"
2356 " ", _("Dump the Kerberos PAC\n"));
2360 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2366 impersonate_princ_s
= argv
[0];
2369 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2371 status
= kerberos_return_pac(mem_ctx
,
2380 2592000, /* one month */
2381 impersonate_princ_s
,
2383 if (!NT_STATUS_IS_OK(status
)) {
2384 d_printf(_("failed to query kerberos PAC: %s\n"),
2389 info
= get_logon_info_from_pac(pac
);
2392 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2393 d_printf(_("The Pac: %s\n"), s
);
2398 TALLOC_FREE(mem_ctx
);
2402 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2404 TALLOC_CTX
*mem_ctx
= NULL
;
2408 if (c
->display_usage
) {
2409 d_printf(_("Usage:\n"),
2410 "net ads kerberos kinit\n"
2411 " ", _("Get Ticket Granting Ticket (TGT) for the user\n"));
2415 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2420 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2422 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2430 2592000, /* one month */
2433 d_printf(_("failed to kinit password: %s\n"),
2440 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2442 struct functable func
[] = {
2445 net_ads_kerberos_kinit
,
2447 N_("Retrieve Ticket Granting Ticket (TGT)"),
2448 N_("net ads kerberos kinit\n"
2449 " Receive Ticket Granting Ticket (TGT)")
2453 net_ads_kerberos_renew
,
2455 N_("Renew Ticket Granting Ticket from credential cache"),
2456 N_("net ads kerberos renew\n"
2457 " Renew Ticket Granting Ticket (TGT) from "
2462 net_ads_kerberos_pac
,
2464 N_("Dump Kerberos PAC"),
2465 N_("net ads kerberos pac\n"
2466 " Dump Kerberos PAC")
2468 {NULL
, NULL
, 0, NULL
, NULL
}
2471 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2474 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2476 struct functable func
[] = {
2481 N_("Display details on remote ADS server"),
2483 " Display details on remote ADS server")
2489 N_("Join the local machine to ADS realm"),
2491 " Join the local machine to ADS realm")
2497 N_("Validate machine account"),
2498 N_("net ads testjoin\n"
2499 " Validate machine account")
2505 N_("Remove the local machine from ADS"),
2506 N_("net ads leave\n"
2507 " Remove the local machine from ADS")
2513 N_("Display machine account details"),
2514 N_("net ads status\n"
2515 " Display machine account details")
2521 N_("List/modify users"),
2523 " List/modify users")
2529 N_("List/modify groups"),
2530 N_("net ads group\n"
2531 " List/modify groups")
2537 N_("Issue dynamic DNS update"),
2539 " Issue dynamic DNS update")
2545 N_("Change user passwords"),
2546 N_("net ads password\n"
2547 " Change user passwords")
2551 net_ads_changetrustpw
,
2553 N_("Change trust account password"),
2554 N_("net ads changetrustpw\n"
2555 " Change trust account password")
2561 N_("List/modify printer entries"),
2562 N_("net ads printer\n"
2563 " List/modify printer entries")
2569 N_("Issue LDAP search using filter"),
2570 N_("net ads search\n"
2571 " Issue LDAP search using filter")
2577 N_("Issue LDAP search by DN"),
2579 " Issue LDAP search by DN")
2585 N_("Issue LDAP search by SID"),
2587 " Issue LDAP search by SID")
2593 N_("Display workgroup name"),
2594 N_("net ads workgroup\n"
2595 " Display the workgroup name")
2601 N_("Perfom CLDAP query on DC"),
2602 N_("net ads lookup\n"
2603 " Find the ADS DC using CLDAP lookups")
2609 N_("Manage local keytab file"),
2610 N_("net ads keytab\n"
2611 " Manage local keytab file")
2617 N_("Manage group policy objects"),
2619 " Manage group policy objects")
2625 N_("Manage kerberos keytab"),
2626 N_("net ads kerberos\n"
2627 " Manage kerberos keytab")
2629 {NULL
, NULL
, 0, NULL
, NULL
}
2632 return net_run_function(c
, argc
, argv
, "net ads", func
);
2637 static int net_ads_noads(void)
2639 d_fprintf(stderr
, _("ADS support not compiled in\n"));
2643 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2645 return net_ads_noads();
2648 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2650 return net_ads_noads();
2653 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2655 return net_ads_noads();
2658 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2660 return net_ads_noads();
2663 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2665 return net_ads_noads();
2668 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2670 return net_ads_noads();
2673 /* this one shouldn't display a message */
2674 int net_ads_check(struct net_context
*c
)
2679 int net_ads_check_our_domain(struct net_context
*c
)
2684 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2686 return net_ads_noads();
2689 #endif /* WITH_ADS */