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"
29 /* when we do not have sufficient input parameters to contact a remote domain
30 * we always fall back to our own realm - Guenther*/
32 static const char *assume_own_realm(struct net_context
*c
)
34 if (!c
->opt_host
&& strequal(lp_workgroup(), c
->opt_target_workgroup
)) {
42 do a cldap netlogon query
44 static int net_ads_cldap_netlogon(struct net_context
*c
, ADS_STRUCT
*ads
)
46 char addr
[INET6_ADDRSTRLEN
];
47 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
49 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
50 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
51 d_fprintf(stderr
, "CLDAP query failed!\n");
55 d_printf("Information for Domain Controller: %s\n\n",
58 d_printf("Response Type: ");
59 switch (reply
.command
) {
60 case LOGON_SAM_LOGON_USER_UNKNOWN_EX
:
61 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
63 case LOGON_SAM_LOGON_RESPONSE_EX
:
64 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
67 d_printf("0x%x\n", reply
.command
);
71 d_printf("GUID: %s\n", GUID_string(talloc_tos(), &reply
.domain_uuid
));
75 "\tIs a GC of the forest: %s\n"
76 "\tIs an LDAP server: %s\n"
78 "\tIs running a KDC: %s\n"
79 "\tIs running time services: %s\n"
80 "\tIs the closest DC: %s\n"
82 "\tHas a hardware clock: %s\n"
83 "\tIs a non-domain NC serviced by LDAP server: %s\n"
84 "\tIs NT6 DC that has some secrets: %s\n"
85 "\tIs NT6 DC that has all secrets: %s\n",
86 (reply
.server_type
& NBT_SERVER_PDC
) ? "yes" : "no",
87 (reply
.server_type
& NBT_SERVER_GC
) ? "yes" : "no",
88 (reply
.server_type
& NBT_SERVER_LDAP
) ? "yes" : "no",
89 (reply
.server_type
& NBT_SERVER_DS
) ? "yes" : "no",
90 (reply
.server_type
& NBT_SERVER_KDC
) ? "yes" : "no",
91 (reply
.server_type
& NBT_SERVER_TIMESERV
) ? "yes" : "no",
92 (reply
.server_type
& NBT_SERVER_CLOSEST
) ? "yes" : "no",
93 (reply
.server_type
& NBT_SERVER_WRITABLE
) ? "yes" : "no",
94 (reply
.server_type
& NBT_SERVER_GOOD_TIMESERV
) ? "yes" : "no",
95 (reply
.server_type
& NBT_SERVER_NDNC
) ? "yes" : "no",
96 (reply
.server_type
& NBT_SERVER_SELECT_SECRET_DOMAIN_6
) ? "yes" : "no",
97 (reply
.server_type
& NBT_SERVER_FULL_SECRET_DOMAIN_6
) ? "yes" : "no");
100 printf("Forest:\t\t\t%s\n", reply
.forest
);
101 printf("Domain:\t\t\t%s\n", reply
.dns_domain
);
102 printf("Domain Controller:\t%s\n", reply
.pdc_dns_name
);
104 printf("Pre-Win2k Domain:\t%s\n", reply
.domain
);
105 printf("Pre-Win2k Hostname:\t%s\n", reply
.pdc_name
);
107 if (*reply
.user_name
) printf("User name:\t%s\n", reply
.user_name
);
109 printf("Server Site Name :\t\t%s\n", reply
.server_site
);
110 printf("Client Site Name :\t\t%s\n", reply
.client_site
);
112 d_printf("NT Version: %d\n", reply
.nt_version
);
113 d_printf("LMNT Token: %.2x\n", reply
.lmnt_token
);
114 d_printf("LM20 Token: %.2x\n", reply
.lm20_token
);
120 this implements the CLDAP based netlogon lookup requests
121 for finding the domain controller of a ADS domain
123 static int net_ads_lookup(struct net_context
*c
, int argc
, const char **argv
)
128 if (c
->display_usage
) {
131 " Find the ADS DC using CLDAP lookup.\n");
135 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
136 d_fprintf(stderr
, "Didn't find the cldap server!\n");
141 if (!ads
->config
.realm
) {
142 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
143 ads
->ldap
.port
= 389;
146 ret
= net_ads_cldap_netlogon(c
, ads
);
153 static int net_ads_info(struct net_context
*c
, int argc
, const char **argv
)
156 char addr
[INET6_ADDRSTRLEN
];
158 if (c
->display_usage
) {
161 " Display information about an Active Directory "
166 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
167 d_fprintf(stderr
, "Didn't find the ldap server!\n");
171 if (!ads
|| !ads
->config
.realm
) {
172 d_fprintf(stderr
, "Didn't find the ldap server!\n");
177 /* Try to set the server's current time since we didn't do a full
178 TCP LDAP session initially */
180 if ( !ADS_ERR_OK(ads_current_time( ads
)) ) {
181 d_fprintf( stderr
, "Failed to get server's current time!\n");
184 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
186 d_printf("LDAP server: %s\n", addr
);
187 d_printf("LDAP server name: %s\n", ads
->config
.ldap_server_name
);
188 d_printf("Realm: %s\n", ads
->config
.realm
);
189 d_printf("Bind Path: %s\n", ads
->config
.bind_path
);
190 d_printf("LDAP port: %d\n", ads
->ldap
.port
);
191 d_printf("Server time: %s\n",
192 http_timestring(talloc_tos(), ads
->config
.current_time
));
194 d_printf("KDC server: %s\n", ads
->auth
.kdc_server
);
195 d_printf("Server time offset: %d\n", ads
->auth
.time_offset
);
201 static void use_in_memory_ccache(void) {
202 /* Use in-memory credentials cache so we do not interfere with
203 * existing credentials */
204 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
207 static ADS_STATUS
ads_startup_int(struct net_context
*c
, bool only_own_domain
,
208 uint32 auth_flags
, ADS_STRUCT
**ads_ret
)
210 ADS_STRUCT
*ads
= NULL
;
212 bool need_password
= false;
213 bool second_time
= false;
215 const char *realm
= NULL
;
216 bool tried_closest_dc
= false;
218 /* lp_realm() should be handled by a command line param,
219 However, the join requires that realm be set in smb.conf
220 and compares our realm with the remote server's so this is
221 ok until someone needs more flexibility */
226 if (only_own_domain
) {
229 realm
= assume_own_realm(c
);
232 ads
= ads_init(realm
, c
->opt_target_workgroup
, c
->opt_host
);
236 set_cmdline_auth_info_getpass(c
->auth_info
);
239 if (get_cmdline_auth_info_got_pass(c
->auth_info
)) {
240 use_in_memory_ccache();
241 SAFE_FREE(ads
->auth
.password
);
242 ads
->auth
.password
= smb_xstrdup(
243 get_cmdline_auth_info_password(c
->auth_info
));
246 ads
->auth
.flags
|= auth_flags
;
247 SAFE_FREE(ads
->auth
.user_name
);
248 ads
->auth
.user_name
= smb_xstrdup(
249 get_cmdline_auth_info_username(c
->auth_info
));
252 * If the username is of the form "name@realm",
253 * extract the realm and convert to upper case.
254 * This is only used to establish the connection.
256 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
258 SAFE_FREE(ads
->auth
.realm
);
259 ads
->auth
.realm
= smb_xstrdup(cp
);
260 strupper_m(ads
->auth
.realm
);
263 status
= ads_connect(ads
);
265 if (!ADS_ERR_OK(status
)) {
267 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
268 NT_STATUS_NO_LOGON_SERVERS
)) {
269 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
274 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
275 need_password
= true;
284 /* when contacting our own domain, make sure we use the closest DC.
285 * This is done by reconnecting to ADS because only the first call to
286 * ads_connect will give us our own sitename */
288 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
290 tried_closest_dc
= true; /* avoid loop */
292 if (!ads_closest_dc(ads
)) {
294 namecache_delete(ads
->server
.realm
, 0x1C);
295 namecache_delete(ads
->server
.workgroup
, 0x1C);
308 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
310 return ads_startup_int(c
, only_own_domain
, 0, ads
);
313 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
315 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
319 Check to see if connection can be made via ads.
320 ads_startup() stores the password in opt_password if it needs to so
321 that rpc or rap can use it without re-prompting.
323 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
328 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
332 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
334 status
= ads_connect(ads
);
335 if ( !ADS_ERR_OK(status
) ) {
343 int net_ads_check_our_domain(struct net_context
*c
)
345 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
348 int net_ads_check(struct net_context
*c
)
350 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
354 determine the netbios workgroup name for a domain
356 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
359 char addr
[INET6_ADDRSTRLEN
];
360 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
362 if (c
->display_usage
) {
364 "net ads workgroup\n"
365 " Print the workgroup name\n");
369 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
370 d_fprintf(stderr
, "Didn't find the cldap server!\n");
374 if (!ads
->config
.realm
) {
375 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
376 ads
->ldap
.port
= 389;
379 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
380 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
381 d_fprintf(stderr
, "CLDAP query failed!\n");
386 d_printf("Workgroup: %s\n", reply
.domain
);
395 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
397 char **disp_fields
= (char **) data_area
;
399 if (!field
) { /* must be end of record */
400 if (disp_fields
[0]) {
401 if (!strchr_m(disp_fields
[0], '$')) {
403 d_printf("%-21.21s %s\n",
404 disp_fields
[0], disp_fields
[1]);
406 d_printf("%s\n", disp_fields
[0]);
409 SAFE_FREE(disp_fields
[0]);
410 SAFE_FREE(disp_fields
[1]);
413 if (!values
) /* must be new field, indicate string field */
415 if (StrCaseCmp(field
, "sAMAccountName") == 0) {
416 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
418 if (StrCaseCmp(field
, "description") == 0)
419 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
423 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
425 return net_user_usage(c
, argc
, argv
);
428 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
433 LDAPMessage
*res
=NULL
;
437 if (argc
< 1 || c
->display_usage
)
438 return net_ads_user_usage(c
, argc
, argv
);
440 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
444 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
446 if (!ADS_ERR_OK(status
)) {
447 d_fprintf(stderr
, "ads_user_add: %s\n", ads_errstr(status
));
451 if (ads_count_replies(ads
, res
)) {
452 d_fprintf(stderr
, "ads_user_add: User %s already exists\n", argv
[0]);
456 if (c
->opt_container
) {
457 ou_str
= SMB_STRDUP(c
->opt_container
);
459 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
462 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
464 if (!ADS_ERR_OK(status
)) {
465 d_fprintf(stderr
, "Could not add user %s: %s\n", argv
[0],
470 /* if no password is to be set, we're done */
472 d_printf("User %s added\n", argv
[0]);
477 /* try setting the password */
478 if (asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
) == -1) {
481 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
482 ads
->auth
.time_offset
);
484 if (ADS_ERR_OK(status
)) {
485 d_printf("User %s added\n", argv
[0]);
490 /* password didn't set, delete account */
491 d_fprintf(stderr
, "Could not add user %s. Error setting password %s\n",
492 argv
[0], ads_errstr(status
));
493 ads_msgfree(ads
, res
);
494 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
495 if (ADS_ERR_OK(status
)) {
496 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
497 ads_del_dn(ads
, userdn
);
503 ads_msgfree(ads
, res
);
509 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
514 const char *attrs
[] = {"memberOf", NULL
};
515 char *searchstring
=NULL
;
519 if (argc
< 1 || c
->display_usage
) {
520 return net_ads_user_usage(c
, argc
, argv
);
523 escaped_user
= escape_ldap_string_alloc(argv
[0]);
526 d_fprintf(stderr
, "ads_user_info: failed to escape user %s\n", argv
[0]);
530 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
531 SAFE_FREE(escaped_user
);
535 if (asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
) == -1) {
536 SAFE_FREE(escaped_user
);
539 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
540 SAFE_FREE(searchstring
);
542 if (!ADS_ERR_OK(rc
)) {
543 d_fprintf(stderr
, "ads_search: %s\n", ads_errstr(rc
));
545 SAFE_FREE(escaped_user
);
549 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
550 (LDAPMessage
*)res
, "memberOf");
555 for (i
=0;grouplist
[i
];i
++) {
556 groupname
= ldap_explode_dn(grouplist
[i
], 1);
557 d_printf("%s\n", groupname
[0]);
558 ldap_value_free(groupname
);
560 ldap_value_free(grouplist
);
563 ads_msgfree(ads
, res
);
565 SAFE_FREE(escaped_user
);
569 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
573 LDAPMessage
*res
= NULL
;
577 return net_ads_user_usage(c
, argc
, argv
);
580 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
584 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
585 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
586 d_printf("User %s does not exist.\n", argv
[0]);
587 ads_msgfree(ads
, res
);
591 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
592 ads_msgfree(ads
, res
);
593 rc
= ads_del_dn(ads
, userdn
);
595 if (ADS_ERR_OK(rc
)) {
596 d_printf("User %s deleted\n", argv
[0]);
600 d_fprintf(stderr
, "Error deleting user %s: %s\n", argv
[0],
606 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
608 struct functable func
[] = {
621 "Display information about an AD user",
622 "net ads user info\n"
623 " Display information about an AD user"
630 "net ads user delete\n"
633 {NULL
, NULL
, 0, NULL
, NULL
}
637 const char *shortattrs
[] = {"sAMAccountName", NULL
};
638 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
639 char *disp_fields
[2] = {NULL
, NULL
};
642 if (c
->display_usage
) {
643 d_printf("Usage:\n");
644 d_printf("net ads user\n"
646 net_display_usage_from_functable(func
);
650 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
654 if (c
->opt_long_list_entries
)
655 d_printf("\nUser name Comment"
656 "\n-----------------------------\n");
658 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
660 "(objectCategory=user)",
661 c
->opt_long_list_entries
? longattrs
:
662 shortattrs
, usergrp_display
,
665 return ADS_ERR_OK(rc
) ? 0 : -1;
668 return net_run_function(c
, argc
, argv
, "net ads user", func
);
671 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
673 return net_group_usage(c
, argc
, argv
);
676 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
680 LDAPMessage
*res
=NULL
;
684 if (argc
< 1 || c
->display_usage
) {
685 return net_ads_group_usage(c
, argc
, argv
);
688 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
692 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
694 if (!ADS_ERR_OK(status
)) {
695 d_fprintf(stderr
, "ads_group_add: %s\n", ads_errstr(status
));
699 if (ads_count_replies(ads
, res
)) {
700 d_fprintf(stderr
, "ads_group_add: Group %s already exists\n", argv
[0]);
704 if (c
->opt_container
) {
705 ou_str
= SMB_STRDUP(c
->opt_container
);
707 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
710 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
712 if (ADS_ERR_OK(status
)) {
713 d_printf("Group %s added\n", argv
[0]);
716 d_fprintf(stderr
, "Could not add group %s: %s\n", argv
[0],
722 ads_msgfree(ads
, res
);
728 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
732 LDAPMessage
*res
= NULL
;
735 if (argc
< 1 || c
->display_usage
) {
736 return net_ads_group_usage(c
, argc
, argv
);
739 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
743 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
744 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
745 d_printf("Group %s does not exist.\n", argv
[0]);
746 ads_msgfree(ads
, res
);
750 groupdn
= ads_get_dn(ads
, talloc_tos(), res
);
751 ads_msgfree(ads
, res
);
752 rc
= ads_del_dn(ads
, groupdn
);
753 TALLOC_FREE(groupdn
);
754 if (ADS_ERR_OK(rc
)) {
755 d_printf("Group %s deleted\n", argv
[0]);
759 d_fprintf(stderr
, "Error deleting group %s: %s\n", argv
[0],
765 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
767 struct functable func
[] = {
773 "net ads group add\n"
780 "Delete an AD group",
781 "net ads group delete\n"
782 " Delete an AD group"
784 {NULL
, NULL
, 0, NULL
, NULL
}
788 const char *shortattrs
[] = {"sAMAccountName", NULL
};
789 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
790 char *disp_fields
[2] = {NULL
, NULL
};
793 if (c
->display_usage
) {
794 d_printf("Usage:\n");
795 d_printf("net ads group\n"
796 " List AD groups\n");
797 net_display_usage_from_functable(func
);
801 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
805 if (c
->opt_long_list_entries
)
806 d_printf("\nGroup name Comment"
807 "\n-----------------------------\n");
808 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
810 "(objectCategory=group)",
811 c
->opt_long_list_entries
? longattrs
:
812 shortattrs
, usergrp_display
,
816 return ADS_ERR_OK(rc
) ? 0 : -1;
818 return net_run_function(c
, argc
, argv
, "net ads group", func
);
821 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
827 if (c
->display_usage
) {
830 " Display machine account details\n");
834 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
838 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
839 if (!ADS_ERR_OK(rc
)) {
840 d_fprintf(stderr
, "ads_find_machine_acct: %s\n", ads_errstr(rc
));
845 if (ads_count_replies(ads
, res
) == 0) {
846 d_fprintf(stderr
, "No machine account for '%s' found\n", global_myname());
856 /*******************************************************************
857 Leave an AD domain. Windows XP disables the machine account.
858 We'll try the same. The old code would do an LDAP delete.
859 That only worked using the machine creds because added the machine
860 with full control to the computer object's ACL.
861 *******************************************************************/
863 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
866 struct libnet_UnjoinCtx
*r
= NULL
;
868 struct user_auth_info
*ai
= c
->auth_info
;
870 if (c
->display_usage
) {
873 " Leave an AD domain\n");
878 d_fprintf(stderr
, "No realm set, are we joined ?\n");
882 if (!(ctx
= talloc_init("net_ads_leave"))) {
883 d_fprintf(stderr
, "Could not initialise talloc context.\n");
887 if (!get_cmdline_auth_info_use_kerberos(ai
)) {
888 use_in_memory_ccache();
891 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
892 if (!W_ERROR_IS_OK(werr
)) {
893 d_fprintf(stderr
, "Could not initialise unjoin context.\n");
897 set_cmdline_auth_info_getpass(ai
);
900 r
->in
.use_kerberos
= get_cmdline_auth_info_use_kerberos(ai
);
901 r
->in
.dc_name
= c
->opt_host
;
902 r
->in
.domain_name
= lp_realm();
903 r
->in
.admin_account
= get_cmdline_auth_info_username(ai
);
904 r
->in
.admin_password
= get_cmdline_auth_info_password(ai
);
905 r
->in
.modify_config
= lp_config_backend_is_registry();
906 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
907 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
909 werr
= libnet_Unjoin(ctx
, r
);
910 if (!W_ERROR_IS_OK(werr
)) {
911 d_printf("Failed to leave domain: %s\n",
912 r
->out
.error_string
? r
->out
.error_string
:
913 get_friendly_werror_msg(werr
));
917 if (W_ERROR_IS_OK(werr
)) {
918 d_printf("Deleted account for '%s' in realm '%s'\n",
919 r
->in
.machine_name
, r
->out
.dns_domain_name
);
923 /* We couldn't delete it - see if the disable succeeded. */
924 if (r
->out
.disabled_machine_account
) {
925 d_printf("Disabled account for '%s' in realm '%s'\n",
926 r
->in
.machine_name
, r
->out
.dns_domain_name
);
931 d_fprintf(stderr
, "Failed to disable machine account for '%s' in realm '%s'\n",
932 r
->in
.machine_name
, r
->out
.dns_domain_name
);
938 if (W_ERROR_IS_OK(werr
)) {
945 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
947 ADS_STRUCT
*ads
= NULL
;
950 if (!secrets_init()) {
951 DEBUG(1,("Failed to initialise secrets database\n"));
952 return NT_STATUS_ACCESS_DENIED
;
955 set_cmdline_auth_info_use_machine_account(c
->auth_info
);
956 set_cmdline_auth_info_machine_account_creds(c
->auth_info
);
958 status
= ads_startup(c
, true, &ads
);
959 if (!ADS_ERR_OK(status
)) {
960 return ads_ntstatus(status
);
968 check that an existing join is OK
970 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
973 use_in_memory_ccache();
975 if (c
->display_usage
) {
978 " Test if the existing join is ok\n");
982 /* Display success or failure */
983 status
= net_ads_join_ok(c
);
984 if (!NT_STATUS_IS_OK(status
)) {
985 fprintf(stderr
,"Join to domain is not valid: %s\n",
986 get_friendly_nt_error_msg(status
));
990 printf("Join is OK\n");
994 /*******************************************************************
995 Simple configu checks before beginning the join
996 ********************************************************************/
998 static WERROR
check_ads_config( void )
1000 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
1001 d_printf("Host is not configured as a member server.\n");
1002 return WERR_INVALID_DOMAIN_ROLE
;
1005 if (strlen(global_myname()) > 15) {
1006 d_printf("Our netbios name can be at most 15 chars long, "
1007 "\"%s\" is %u chars long\n", global_myname(),
1008 (unsigned int)strlen(global_myname()));
1009 return WERR_INVALID_COMPUTERNAME
;
1012 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1013 d_fprintf(stderr
, "realm must be set in in %s for ADS "
1014 "join to succeed.\n", get_dyn_CONFIGFILE());
1015 return WERR_INVALID_PARAM
;
1021 /*******************************************************************
1022 Send a DNS update request
1023 *******************************************************************/
1025 #if defined(WITH_DNS_UPDATES)
1027 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
1028 const char *pszDomainName
, const char *pszHostName
,
1029 const struct sockaddr_storage
*sslist
,
1032 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1033 const char *machine_name
,
1034 const struct sockaddr_storage
*addrs
,
1037 struct dns_rr_ns
*nameservers
= NULL
;
1039 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1042 const char *dnsdomain
= NULL
;
1043 char *root_domain
= NULL
;
1045 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1046 d_printf("No DNS domain configured for %s. "
1047 "Unable to perform DNS Update.\n", machine_name
);
1048 status
= NT_STATUS_INVALID_PARAMETER
;
1053 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
1054 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1055 /* Child domains often do not have NS records. Look
1056 for the NS record for the forest root domain
1057 (rootDomainNamingContext in therootDSE) */
1059 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1060 LDAPMessage
*msg
= NULL
;
1062 ADS_STATUS ads_status
;
1064 if ( !ads
->ldap
.ld
) {
1065 ads_status
= ads_connect( ads
);
1066 if ( !ADS_ERR_OK(ads_status
) ) {
1067 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1072 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1073 "(objectclass=*)", rootname_attrs
, &msg
);
1074 if (!ADS_ERR_OK(ads_status
)) {
1078 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1080 ads_msgfree( ads
, msg
);
1084 root_domain
= ads_build_domain( root_dn
);
1087 ads_msgfree( ads
, msg
);
1089 /* try again for NS servers */
1091 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1093 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1094 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1095 "realm\n", ads
->config
.realm
));
1099 dnsdomain
= root_domain
;
1103 /* Now perform the dns update - we'll try non-secure and if we fail,
1104 we'll follow it up with a secure update */
1106 fstrcpy( dns_server
, nameservers
[0].hostname
);
1108 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1109 if (!ERR_DNS_IS_OK(dns_err
)) {
1110 status
= NT_STATUS_UNSUCCESSFUL
;
1115 SAFE_FREE( root_domain
);
1120 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
)
1123 struct sockaddr_storage
*iplist
= NULL
;
1124 fstring machine_name
;
1127 name_to_fqdn( machine_name
, global_myname() );
1128 strlower_m( machine_name
);
1130 /* Get our ip address (not the 127.0.0.x address but a real ip
1133 num_addrs
= get_my_ip_address( &iplist
);
1134 if ( num_addrs
<= 0 ) {
1135 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1137 return NT_STATUS_INVALID_PARAMETER
;
1140 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1142 SAFE_FREE( iplist
);
1148 /*******************************************************************
1149 ********************************************************************/
1151 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1153 d_printf("net ads join [options]\n");
1154 d_printf("Valid options:\n");
1155 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1156 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1157 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1158 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1159 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1160 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1161 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1162 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1163 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1164 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1165 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1166 d_printf(" the two other attributes.\n");
1171 /*******************************************************************
1172 ********************************************************************/
1174 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1176 TALLOC_CTX
*ctx
= NULL
;
1177 struct libnet_JoinCtx
*r
= NULL
;
1178 const char *domain
= lp_realm();
1179 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1180 bool createupn
= false;
1181 const char *machineupn
= NULL
;
1182 const char *create_in_ou
= NULL
;
1184 const char *os_name
= NULL
;
1185 const char *os_version
= NULL
;
1186 bool modify_config
= lp_config_backend_is_registry();
1187 struct user_auth_info
*ai
= c
->auth_info
;;
1189 if (c
->display_usage
)
1190 return net_ads_join_usage(c
, argc
, argv
);
1192 if (!modify_config
) {
1194 werr
= check_ads_config();
1195 if (!W_ERROR_IS_OK(werr
)) {
1196 d_fprintf(stderr
, "Invalid configuration. Exiting....\n");
1201 if (!(ctx
= talloc_init("net_ads_join"))) {
1202 d_fprintf(stderr
, "Could not initialise talloc context.\n");
1207 if (!get_cmdline_auth_info_use_kerberos(ai
)) {
1208 use_in_memory_ccache();
1211 werr
= libnet_init_JoinCtx(ctx
, &r
);
1212 if (!W_ERROR_IS_OK(werr
)) {
1216 /* process additional command line args */
1218 for ( i
=0; i
<argc
; i
++ ) {
1219 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1221 machineupn
= get_string_param(argv
[i
]);
1223 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1224 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1225 d_fprintf(stderr
, "Please supply a valid OU path.\n");
1226 werr
= WERR_INVALID_PARAM
;
1230 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1231 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1232 d_fprintf(stderr
, "Please supply a operating system name.\n");
1233 werr
= WERR_INVALID_PARAM
;
1237 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1238 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1239 d_fprintf(stderr
, "Please supply a valid operating system version.\n");
1240 werr
= WERR_INVALID_PARAM
;
1250 d_fprintf(stderr
, "Please supply a valid domain name\n");
1251 werr
= WERR_INVALID_PARAM
;
1255 /* Do the domain join here */
1257 set_cmdline_auth_info_getpass(ai
);
1259 r
->in
.domain_name
= domain
;
1260 r
->in
.create_upn
= createupn
;
1261 r
->in
.upn
= machineupn
;
1262 r
->in
.account_ou
= create_in_ou
;
1263 r
->in
.os_name
= os_name
;
1264 r
->in
.os_version
= os_version
;
1265 r
->in
.dc_name
= c
->opt_host
;
1266 r
->in
.admin_account
= get_cmdline_auth_info_username(ai
);
1267 r
->in
.admin_password
= get_cmdline_auth_info_password(ai
);
1269 r
->in
.use_kerberos
= get_cmdline_auth_info_use_kerberos(ai
);
1270 r
->in
.modify_config
= modify_config
;
1271 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1272 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1273 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1275 werr
= libnet_Join(ctx
, r
);
1276 if (!W_ERROR_IS_OK(werr
)) {
1280 /* Check the short name of the domain */
1282 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1283 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1284 d_printf("domain name obtained from the server.\n");
1285 d_printf("Using the name [%s] from the server.\n", r
->out
.netbios_domain_name
);
1286 d_printf("You should set \"workgroup = %s\" in %s.\n",
1287 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1290 d_printf("Using short domain name -- %s\n", r
->out
.netbios_domain_name
);
1292 if (r
->out
.dns_domain_name
) {
1293 d_printf("Joined '%s' to realm '%s'\n", r
->in
.machine_name
,
1294 r
->out
.dns_domain_name
);
1296 d_printf("Joined '%s' to domain '%s'\n", r
->in
.machine_name
,
1297 r
->out
.netbios_domain_name
);
1300 #if defined(WITH_DNS_UPDATES)
1301 if (r
->out
.domain_is_ad
) {
1302 /* We enter this block with user creds */
1303 ADS_STRUCT
*ads_dns
= NULL
;
1305 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1306 /* kinit with the machine password */
1308 use_in_memory_ccache();
1309 if (asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname()) == -1) {
1312 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1313 r
->out
.netbios_domain_name
, NULL
, NULL
);
1314 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1315 strupper_m(ads_dns
->auth
.realm
);
1316 ads_kinit_password( ads_dns
);
1319 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns( ctx
, ads_dns
)) ) {
1320 d_fprintf( stderr
, "DNS update failed!\n" );
1323 /* exit from this block using machine creds */
1324 ads_destroy(&ads_dns
);
1333 /* issue an overall failure message at the end. */
1334 d_printf("Failed to join domain: %s\n",
1335 r
&& r
->out
.error_string
? r
->out
.error_string
:
1336 get_friendly_werror_msg(werr
));
1342 /*******************************************************************
1343 ********************************************************************/
1345 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1347 #if defined(WITH_DNS_UPDATES)
1353 talloc_enable_leak_report();
1356 if (argc
> 0 || c
->display_usage
) {
1358 "net ads dns register\n"
1359 " Register hostname with DNS\n");
1363 if (!(ctx
= talloc_init("net_ads_dns"))) {
1364 d_fprintf(stderr
, "Could not initialise talloc context\n");
1368 status
= ads_startup(c
, true, &ads
);
1369 if ( !ADS_ERR_OK(status
) ) {
1370 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1375 if ( !NT_STATUS_IS_OK(net_update_dns(ctx
, ads
)) ) {
1376 d_fprintf( stderr
, "DNS update failed!\n" );
1377 ads_destroy( &ads
);
1382 d_fprintf( stderr
, "Successfully registered hostname with DNS\n" );
1389 d_fprintf(stderr
, "DNS update support not enabled at compile time!\n");
1394 #if defined(WITH_DNS_UPDATES)
1395 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1398 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1400 #if defined(WITH_DNS_UPDATES)
1404 talloc_enable_leak_report();
1407 if (argc
!= 2 || c
->display_usage
) {
1409 "net ads dns gethostbyname <server> <name>\n"
1410 " Look up hostname from the AD\n"
1411 " server\tName server to use\n"
1412 " name\tName to look up\n");
1416 err
= do_gethostbyname(argv
[0], argv
[1]);
1418 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err
));
1423 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1425 struct functable func
[] = {
1428 net_ads_dns_register
,
1430 "Add host dns entry to AD",
1431 "net ads dns register\n"
1432 " Add host dns entry to AD"
1436 net_ads_dns_gethostbyname
,
1439 "net ads dns gethostbyname\n"
1442 {NULL
, NULL
, 0, NULL
, NULL
}
1445 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1448 /*******************************************************************
1449 ********************************************************************/
1451 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1454 "\nnet ads printer search <printer>"
1455 "\n\tsearch for a printer in the directory\n"
1456 "\nnet ads printer info <printer> <server>"
1457 "\n\tlookup info in directory for printer on server"
1458 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1459 "\nnet ads printer publish <printername>"
1460 "\n\tpublish printer in directory"
1461 "\n\t(note: printer name is required)\n"
1462 "\nnet ads printer remove <printername>"
1463 "\n\tremove printer from directory"
1464 "\n\t(note: printer name is required)\n");
1468 /*******************************************************************
1469 ********************************************************************/
1471 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1475 LDAPMessage
*res
= NULL
;
1477 if (c
->display_usage
) {
1479 "net ads printer search\n"
1480 " List printers in the AD\n");
1484 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1488 rc
= ads_find_printers(ads
, &res
);
1490 if (!ADS_ERR_OK(rc
)) {
1491 d_fprintf(stderr
, "ads_find_printer: %s\n", ads_errstr(rc
));
1492 ads_msgfree(ads
, res
);
1497 if (ads_count_replies(ads
, res
) == 0) {
1498 d_fprintf(stderr
, "No results found\n");
1499 ads_msgfree(ads
, res
);
1505 ads_msgfree(ads
, res
);
1510 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1514 const char *servername
, *printername
;
1515 LDAPMessage
*res
= NULL
;
1517 if (c
->display_usage
) {
1519 "net ads printer info [printername [servername]]\n"
1520 " Display printer info from AD\n"
1521 " printername\tPrinter name or wildcard\n"
1522 " servername\tName of the print server\n");
1526 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1531 printername
= argv
[0];
1537 servername
= argv
[1];
1539 servername
= global_myname();
1542 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1544 if (!ADS_ERR_OK(rc
)) {
1545 d_fprintf(stderr
, "Server '%s' not found: %s\n",
1546 servername
, ads_errstr(rc
));
1547 ads_msgfree(ads
, res
);
1552 if (ads_count_replies(ads
, res
) == 0) {
1553 d_fprintf(stderr
, "Printer '%s' not found\n", printername
);
1554 ads_msgfree(ads
, res
);
1560 ads_msgfree(ads
, res
);
1566 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1570 const char *servername
, *printername
;
1571 struct cli_state
*cli
;
1572 struct rpc_pipe_client
*pipe_hnd
;
1573 struct sockaddr_storage server_ss
;
1575 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1576 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1577 char *prt_dn
, *srv_dn
, **srv_cn
;
1578 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1579 LDAPMessage
*res
= NULL
;
1580 struct user_auth_info
*ai
= c
->auth_info
;
1582 if (argc
< 1 || c
->display_usage
) {
1584 "net ads printer publish <printername> [servername]\n"
1585 " Publish printer in AD\n"
1586 " printername\tName of the printer\n"
1587 " servername\tName of the print server\n");
1588 talloc_destroy(mem_ctx
);
1592 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1593 talloc_destroy(mem_ctx
);
1597 printername
= argv
[0];
1600 servername
= argv
[1];
1602 servername
= global_myname();
1605 /* Get printer data from SPOOLSS */
1607 resolve_name(servername
, &server_ss
, 0x20);
1609 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1612 get_cmdline_auth_info_username(ai
),
1614 get_cmdline_auth_info_password(ai
),
1615 CLI_FULL_CONNECTION_USE_KERBEROS
,
1618 if (NT_STATUS_IS_ERR(nt_status
)) {
1619 d_fprintf(stderr
, "Unable to open a connnection to %s to obtain data "
1620 "for %s\n", servername
, printername
);
1622 talloc_destroy(mem_ctx
);
1626 /* Publish on AD server */
1628 ads_find_machine_acct(ads
, &res
, servername
);
1630 if (ads_count_replies(ads
, res
) == 0) {
1631 d_fprintf(stderr
, "Could not find machine account for server %s\n",
1634 talloc_destroy(mem_ctx
);
1638 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1639 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1641 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1642 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1643 if (!srv_cn_escaped
|| !printername_escaped
) {
1644 SAFE_FREE(srv_cn_escaped
);
1645 SAFE_FREE(printername_escaped
);
1646 d_fprintf(stderr
, "Internal error, out of memory!");
1648 talloc_destroy(mem_ctx
);
1652 if (asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
) == -1) {
1653 SAFE_FREE(srv_cn_escaped
);
1654 SAFE_FREE(printername_escaped
);
1655 d_fprintf(stderr
, "Internal error, out of memory!");
1657 talloc_destroy(mem_ctx
);
1661 SAFE_FREE(srv_cn_escaped
);
1662 SAFE_FREE(printername_escaped
);
1664 nt_status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_spoolss
.syntax_id
, &pipe_hnd
);
1665 if (!NT_STATUS_IS_OK(nt_status
)) {
1666 d_fprintf(stderr
, "Unable to open a connnection to the spoolss pipe on %s\n",
1670 talloc_destroy(mem_ctx
);
1674 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1678 talloc_destroy(mem_ctx
);
1682 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1683 if (!ADS_ERR_OK(rc
)) {
1684 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1687 talloc_destroy(mem_ctx
);
1691 d_printf("published printer\n");
1694 talloc_destroy(mem_ctx
);
1699 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1703 const char *servername
;
1705 LDAPMessage
*res
= NULL
;
1707 if (argc
< 1 || c
->display_usage
) {
1709 "net ads printer remove <printername> [servername]\n"
1710 " Remove a printer from the AD\n"
1711 " printername\tName of the printer\n"
1712 " servername\tName of the print server\n");
1716 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1721 servername
= argv
[1];
1723 servername
= global_myname();
1726 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1728 if (!ADS_ERR_OK(rc
)) {
1729 d_fprintf(stderr
, "ads_find_printer_on_server: %s\n", ads_errstr(rc
));
1730 ads_msgfree(ads
, res
);
1735 if (ads_count_replies(ads
, res
) == 0) {
1736 d_fprintf(stderr
, "Printer '%s' not found\n", argv
[1]);
1737 ads_msgfree(ads
, res
);
1742 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
1743 ads_msgfree(ads
, res
);
1744 rc
= ads_del_dn(ads
, prt_dn
);
1745 TALLOC_FREE(prt_dn
);
1747 if (!ADS_ERR_OK(rc
)) {
1748 d_fprintf(stderr
, "ads_del_dn: %s\n", ads_errstr(rc
));
1757 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
1759 struct functable func
[] = {
1762 net_ads_printer_search
,
1764 "Search for a printer",
1765 "net ads printer search\n"
1766 " Search for a printer"
1770 net_ads_printer_info
,
1772 "Display printer information",
1773 "net ads printer info\n"
1774 " Display printer information"
1778 net_ads_printer_publish
,
1780 "Publish a printer",
1781 "net ads printer publish\n"
1782 " Publish a printer"
1786 net_ads_printer_remove
,
1789 "net ads printer remove\n"
1792 {NULL
, NULL
, 0, NULL
, NULL
}
1795 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
1799 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
1802 const char *auth_principal
;
1803 const char *auth_password
;
1805 char *new_password
= NULL
;
1810 if (c
->display_usage
) {
1812 "net ads password <username>\n"
1813 " Change password for user\n"
1814 " username\tName of user to change password for\n");
1818 auth_principal
= get_cmdline_auth_info_username(c
->auth_info
);
1819 set_cmdline_auth_info_getpass(c
->auth_info
);
1820 auth_password
= get_cmdline_auth_info_password(c
->auth_info
);
1823 d_fprintf(stderr
, "ERROR: You must say which username to change password for\n");
1828 if (!strchr_m(user
, '@')) {
1829 if (asprintf(&chr
, "%s@%s", argv
[0], lp_realm()) == -1) {
1835 use_in_memory_ccache();
1836 chr
= strchr_m(auth_principal
, '@');
1843 /* use the realm so we can eventually change passwords for users
1844 in realms other than default */
1845 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
1849 /* we don't actually need a full connect, but it's the easy way to
1850 fill in the KDC's addresss */
1853 if (!ads
->config
.realm
) {
1854 d_fprintf(stderr
, "Didn't find the kerberos server!\n");
1860 new_password
= (char *)argv
[1];
1862 if (asprintf(&prompt
, "Enter new password for %s:", user
) == -1) {
1865 new_password
= getpass(prompt
);
1869 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
1870 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
1871 if (!ADS_ERR_OK(ret
)) {
1872 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1877 d_printf("Password change for %s completed.\n", user
);
1883 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
1886 char *host_principal
;
1890 if (c
->display_usage
) {
1892 "net ads changetrustpw\n"
1893 " Change the machine account's trust password\n");
1897 if (!secrets_init()) {
1898 DEBUG(1,("Failed to initialise secrets database\n"));
1902 set_cmdline_auth_info_use_machine_account(c
->auth_info
);
1904 use_in_memory_ccache();
1906 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1910 fstrcpy(my_name
, global_myname());
1911 strlower_m(my_name
);
1912 if (asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
) == -1) {
1916 d_printf("Changing password for principal: %s\n", host_principal
);
1918 ret
= ads_change_trust_account_password(ads
, host_principal
);
1920 if (!ADS_ERR_OK(ret
)) {
1921 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1923 SAFE_FREE(host_principal
);
1927 d_printf("Password change for principal %s succeeded.\n", host_principal
);
1929 if (USE_SYSTEM_KEYTAB
) {
1930 d_printf("Attempting to update system keytab with new password.\n");
1931 if (ads_keytab_create_default(ads
)) {
1932 d_printf("Failed to update system keytab.\n");
1937 SAFE_FREE(host_principal
);
1943 help for net ads search
1945 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
1948 "\nnet ads search <expression> <attributes...>\n"
1949 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1950 "The expression is a standard LDAP search expression, and the\n"
1951 "attributes are a list of LDAP fields to show in the results.\n\n"
1952 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1954 net_common_flags_usage(c
, argc
, argv
);
1960 general ADS search function. Useful in diagnosing problems in ADS
1962 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
1966 const char *ldap_exp
;
1968 LDAPMessage
*res
= NULL
;
1970 if (argc
< 1 || c
->display_usage
) {
1971 return net_ads_search_usage(c
, argc
, argv
);
1974 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1981 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
1983 ldap_exp
, attrs
, &res
);
1984 if (!ADS_ERR_OK(rc
)) {
1985 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
1990 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
1992 /* dump the results */
1995 ads_msgfree(ads
, res
);
2003 help for net ads search
2005 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
2008 "\nnet ads dn <dn> <attributes...>\n"
2009 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2010 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2011 "to show in the results\n\n"
2012 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2013 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2015 net_common_flags_usage(c
, argc
, argv
);
2021 general ADS search function. Useful in diagnosing problems in ADS
2023 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
2029 LDAPMessage
*res
= NULL
;
2031 if (argc
< 1 || c
->display_usage
) {
2032 return net_ads_dn_usage(c
, argc
, argv
);
2035 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2042 rc
= ads_do_search_all(ads
, dn
,
2044 "(objectclass=*)", attrs
, &res
);
2045 if (!ADS_ERR_OK(rc
)) {
2046 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
2051 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2053 /* dump the results */
2056 ads_msgfree(ads
, res
);
2063 help for net ads sid search
2065 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2068 "\nnet ads sid <sid> <attributes...>\n"
2069 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2070 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2071 "to show in the results\n\n"
2072 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2074 net_common_flags_usage(c
, argc
, argv
);
2080 general ADS search function. Useful in diagnosing problems in ADS
2082 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2086 const char *sid_string
;
2088 LDAPMessage
*res
= NULL
;
2091 if (argc
< 1 || c
->display_usage
) {
2092 return net_ads_sid_usage(c
, argc
, argv
);
2095 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2099 sid_string
= argv
[0];
2102 if (!string_to_sid(&sid
, sid_string
)) {
2103 d_fprintf(stderr
, "could not convert sid\n");
2108 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2109 if (!ADS_ERR_OK(rc
)) {
2110 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
2115 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2117 /* dump the results */
2120 ads_msgfree(ads
, res
);
2126 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2131 if (c
->display_usage
) {
2133 "net ads keytab flush\n"
2134 " Delete the whole keytab\n");
2138 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2141 ret
= ads_keytab_flush(ads
);
2146 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2152 if (c
->display_usage
) {
2154 "net ads keytab add <principal> [principal ...]\n"
2155 " Add principals to local keytab\n"
2156 " principal\tKerberos principal to add to "
2161 d_printf("Processing principals to add...\n");
2162 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2165 for (i
= 0; i
< argc
; i
++) {
2166 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2172 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2177 if (c
->display_usage
) {
2179 "net ads keytab create\n"
2180 " Create new default keytab\n");
2184 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2187 ret
= ads_keytab_create_default(ads
);
2192 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2194 const char *keytab
= NULL
;
2196 if (c
->display_usage
) {
2198 "net ads keytab list [keytab]\n"
2199 " List a local keytab\n"
2200 " keytab\tKeytab to list\n");
2208 return ads_keytab_list(keytab
);
2212 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2214 struct functable func
[] = {
2219 "Add a service principal",
2220 "net ads keytab add\n"
2221 " Add a service principal"
2225 net_ads_keytab_create
,
2227 "Create a fresh keytab",
2228 "net ads keytab create\n"
2229 " Create a fresh keytab"
2233 net_ads_keytab_flush
,
2235 "Remove all keytab entries",
2236 "net ads keytab flush\n"
2237 " Remove all keytab entries"
2241 net_ads_keytab_list
,
2244 "net ads keytab list\n"
2247 {NULL
, NULL
, 0, NULL
, NULL
}
2250 if (!USE_KERBEROS_KEYTAB
) {
2251 d_printf("\nWarning: \"kerberos method\" must be set to a "
2252 "keytab method to use keytab functions.\n");
2255 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2258 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2262 if (c
->display_usage
) {
2264 "net ads kerberos renew\n"
2265 " Renew TGT from existing credential cache\n");
2269 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2271 d_printf("failed to renew kerberos ticket: %s\n",
2272 error_message(ret
));
2277 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2279 struct PAC_DATA
*pac
= NULL
;
2280 struct PAC_LOGON_INFO
*info
= NULL
;
2281 TALLOC_CTX
*mem_ctx
= NULL
;
2284 struct user_auth_info
*ai
= c
->auth_info
;
2286 if (c
->display_usage
) {
2288 "net ads kerberos pac\n"
2289 " Dump the Kerberos PAC\n");
2293 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2298 set_cmdline_auth_info_getpass(ai
);
2300 status
= kerberos_return_pac(mem_ctx
,
2301 get_cmdline_auth_info_username(ai
),
2302 get_cmdline_auth_info_password(ai
),
2309 2592000, /* one month */
2311 if (!NT_STATUS_IS_OK(status
)) {
2312 d_printf("failed to query kerberos PAC: %s\n",
2317 info
= get_logon_info_from_pac(pac
);
2320 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2321 d_printf("The Pac: %s\n", s
);
2326 TALLOC_FREE(mem_ctx
);
2330 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2332 TALLOC_CTX
*mem_ctx
= NULL
;
2335 struct user_auth_info
*ai
= c
->auth_info
;
2337 if (c
->display_usage
) {
2339 "net ads kerberos kinit\n"
2340 " Get Ticket Granting Ticket (TGT) for the user\n");
2344 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2349 set_cmdline_auth_info_getpass(ai
);
2351 ret
= kerberos_kinit_password_ext(get_cmdline_auth_info_username(ai
),
2352 get_cmdline_auth_info_password(ai
),
2359 2592000, /* one month */
2362 d_printf("failed to kinit password: %s\n",
2369 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2371 struct functable func
[] = {
2374 net_ads_kerberos_kinit
,
2376 "Retrieve Ticket Granting Ticket (TGT)",
2377 "net ads kerberos kinit\n"
2378 " Receive Ticket Granting Ticket (TGT)"
2382 net_ads_kerberos_renew
,
2384 "Renew Ticket Granting Ticket from credential cache"
2385 "net ads kerberos renew\n"
2386 " Renew Ticket Granting Ticket from credential cache"
2390 net_ads_kerberos_pac
,
2392 "Dump Kerberos PAC",
2393 "net ads kerberos pac\n"
2394 " Dump Kerberos PAC"
2396 {NULL
, NULL
, 0, NULL
, NULL
}
2399 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2402 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2404 struct functable func
[] = {
2409 "Display details on remote ADS server",
2411 " Display details on remote ADS server"
2417 "Join the local machine to ADS realm",
2419 " Join the local machine to ADS realm"
2425 "Validate machine account",
2426 "net ads testjoin\n"
2427 " Validate machine account"
2433 "Remove the local machine from ADS",
2435 " Remove the local machine from ADS"
2441 "Display machine account details",
2443 " Display machine account details"
2449 "List/modify users",
2451 " List/modify users"
2457 "List/modify groups",
2459 " List/modify groups"
2465 "Issue dynamic DNS update",
2467 " Issue dynamic DNS update"
2473 "Change user passwords",
2474 "net ads password\n"
2475 " Change user passwords"
2479 net_ads_changetrustpw
,
2481 "Change trust account password",
2482 "net ads changetrustpw\n"
2483 " Change trust account password"
2489 "List/modify printer entries",
2491 " List/modify printer entries"
2497 "Issue LDAP search using filter",
2499 " Issue LDAP search using filter"
2505 "Issue LDAP search by DN",
2507 " Issue LDAP search by DN"
2513 "Issue LDAP search by SID",
2515 " Issue LDAP search by SID"
2521 "Display workgroup name",
2522 "net ads workgroup\n"
2523 " Display the workgroup name"
2529 "Perfom CLDAP query on DC",
2531 " Find the ADS DC using CLDAP lookups"
2537 "Manage local keytab file",
2539 " Manage local keytab file"
2545 "Manage group policy objects",
2547 " Manage group policy objects"
2553 "Manage kerberos keytab",
2554 "net ads kerberos\n"
2555 " Manage kerberos keytab"
2557 {NULL
, NULL
, 0, NULL
, NULL
}
2560 return net_run_function(c
, argc
, argv
, "net ads", func
);
2565 static int net_ads_noads(void)
2567 d_fprintf(stderr
, "ADS support not compiled in\n");
2571 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2573 return net_ads_noads();
2576 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2578 return net_ads_noads();
2581 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2583 return net_ads_noads();
2586 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2588 return net_ads_noads();
2591 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2593 return net_ads_noads();
2596 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2598 return net_ads_noads();
2601 /* this one shouldn't display a message */
2602 int net_ads_check(struct net_context
*c
)
2607 int net_ads_check_our_domain(struct net_context
*c
)
2612 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2614 return net_ads_noads();
2617 #endif /* WITH_ADS */