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
);
234 if (!c
->opt_user_name
) {
235 c
->opt_user_name
= "administrator";
238 if (c
->opt_user_specified
) {
239 need_password
= true;
243 if (!c
->opt_password
&& need_password
&& !c
->opt_machine_pass
) {
244 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
245 if (!c
->opt_password
) {
247 return ADS_ERROR(LDAP_NO_MEMORY
);
251 if (c
->opt_password
) {
252 use_in_memory_ccache();
253 SAFE_FREE(ads
->auth
.password
);
254 ads
->auth
.password
= smb_xstrdup(c
->opt_password
);
257 ads
->auth
.flags
|= auth_flags
;
258 SAFE_FREE(ads
->auth
.user_name
);
259 ads
->auth
.user_name
= smb_xstrdup(c
->opt_user_name
);
262 * If the username is of the form "name@realm",
263 * extract the realm and convert to upper case.
264 * This is only used to establish the connection.
266 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
268 SAFE_FREE(ads
->auth
.realm
);
269 ads
->auth
.realm
= smb_xstrdup(cp
);
270 strupper_m(ads
->auth
.realm
);
273 status
= ads_connect(ads
);
275 if (!ADS_ERR_OK(status
)) {
277 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
278 NT_STATUS_NO_LOGON_SERVERS
)) {
279 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
284 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
285 need_password
= true;
294 /* when contacting our own domain, make sure we use the closest DC.
295 * This is done by reconnecting to ADS because only the first call to
296 * ads_connect will give us our own sitename */
298 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
300 tried_closest_dc
= true; /* avoid loop */
302 if (!ads_closest_dc(ads
)) {
304 namecache_delete(ads
->server
.realm
, 0x1C);
305 namecache_delete(ads
->server
.workgroup
, 0x1C);
318 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
320 return ads_startup_int(c
, only_own_domain
, 0, ads
);
323 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
325 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
329 Check to see if connection can be made via ads.
330 ads_startup() stores the password in opt_password if it needs to so
331 that rpc or rap can use it without re-prompting.
333 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
338 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
342 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
344 status
= ads_connect(ads
);
345 if ( !ADS_ERR_OK(status
) ) {
353 int net_ads_check_our_domain(struct net_context
*c
)
355 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
358 int net_ads_check(struct net_context
*c
)
360 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
364 determine the netbios workgroup name for a domain
366 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
369 char addr
[INET6_ADDRSTRLEN
];
370 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
372 if (c
->display_usage
) {
374 "net ads workgroup\n"
375 " Print the workgroup name\n");
379 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
380 d_fprintf(stderr
, "Didn't find the cldap server!\n");
384 if (!ads
->config
.realm
) {
385 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
386 ads
->ldap
.port
= 389;
389 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
390 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
391 d_fprintf(stderr
, "CLDAP query failed!\n");
396 d_printf("Workgroup: %s\n", reply
.domain
);
405 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
407 char **disp_fields
= (char **) data_area
;
409 if (!field
) { /* must be end of record */
410 if (disp_fields
[0]) {
411 if (!strchr_m(disp_fields
[0], '$')) {
413 d_printf("%-21.21s %s\n",
414 disp_fields
[0], disp_fields
[1]);
416 d_printf("%s\n", disp_fields
[0]);
419 SAFE_FREE(disp_fields
[0]);
420 SAFE_FREE(disp_fields
[1]);
423 if (!values
) /* must be new field, indicate string field */
425 if (StrCaseCmp(field
, "sAMAccountName") == 0) {
426 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
428 if (StrCaseCmp(field
, "description") == 0)
429 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
433 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
435 return net_user_usage(c
, argc
, argv
);
438 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
443 LDAPMessage
*res
=NULL
;
447 if (argc
< 1 || c
->display_usage
)
448 return net_ads_user_usage(c
, argc
, argv
);
450 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
454 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
456 if (!ADS_ERR_OK(status
)) {
457 d_fprintf(stderr
, "ads_user_add: %s\n", ads_errstr(status
));
461 if (ads_count_replies(ads
, res
)) {
462 d_fprintf(stderr
, "ads_user_add: User %s already exists\n", argv
[0]);
466 if (c
->opt_container
) {
467 ou_str
= SMB_STRDUP(c
->opt_container
);
469 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
472 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
474 if (!ADS_ERR_OK(status
)) {
475 d_fprintf(stderr
, "Could not add user %s: %s\n", argv
[0],
480 /* if no password is to be set, we're done */
482 d_printf("User %s added\n", argv
[0]);
487 /* try setting the password */
488 if (asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
) == -1) {
491 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
492 ads
->auth
.time_offset
);
494 if (ADS_ERR_OK(status
)) {
495 d_printf("User %s added\n", argv
[0]);
500 /* password didn't set, delete account */
501 d_fprintf(stderr
, "Could not add user %s. Error setting password %s\n",
502 argv
[0], ads_errstr(status
));
503 ads_msgfree(ads
, res
);
504 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
505 if (ADS_ERR_OK(status
)) {
506 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
507 ads_del_dn(ads
, userdn
);
513 ads_msgfree(ads
, res
);
519 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
524 const char *attrs
[] = {"memberOf", NULL
};
525 char *searchstring
=NULL
;
529 if (argc
< 1 || c
->display_usage
) {
530 return net_ads_user_usage(c
, argc
, argv
);
533 escaped_user
= escape_ldap_string(talloc_tos(), argv
[0]);
536 d_fprintf(stderr
, "ads_user_info: failed to escape user %s\n", argv
[0]);
540 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
541 TALLOC_FREE(escaped_user
);
545 if (asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
) == -1) {
546 TALLOC_FREE(escaped_user
);
549 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
550 SAFE_FREE(searchstring
);
552 if (!ADS_ERR_OK(rc
)) {
553 d_fprintf(stderr
, "ads_search: %s\n", ads_errstr(rc
));
555 TALLOC_FREE(escaped_user
);
559 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
560 (LDAPMessage
*)res
, "memberOf");
565 for (i
=0;grouplist
[i
];i
++) {
566 groupname
= ldap_explode_dn(grouplist
[i
], 1);
567 d_printf("%s\n", groupname
[0]);
568 ldap_value_free(groupname
);
570 ldap_value_free(grouplist
);
573 ads_msgfree(ads
, res
);
575 TALLOC_FREE(escaped_user
);
579 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
583 LDAPMessage
*res
= NULL
;
587 return net_ads_user_usage(c
, argc
, argv
);
590 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
594 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
595 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
596 d_printf("User %s does not exist.\n", argv
[0]);
597 ads_msgfree(ads
, res
);
601 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
602 ads_msgfree(ads
, res
);
603 rc
= ads_del_dn(ads
, userdn
);
605 if (ADS_ERR_OK(rc
)) {
606 d_printf("User %s deleted\n", argv
[0]);
610 d_fprintf(stderr
, "Error deleting user %s: %s\n", argv
[0],
616 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
618 struct functable func
[] = {
631 "Display information about an AD user",
632 "net ads user info\n"
633 " Display information about an AD user"
640 "net ads user delete\n"
643 {NULL
, NULL
, 0, NULL
, NULL
}
647 const char *shortattrs
[] = {"sAMAccountName", NULL
};
648 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
649 char *disp_fields
[2] = {NULL
, NULL
};
652 if (c
->display_usage
) {
653 d_printf("Usage:\n");
654 d_printf("net ads user\n"
656 net_display_usage_from_functable(func
);
660 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
664 if (c
->opt_long_list_entries
)
665 d_printf("\nUser name Comment"
666 "\n-----------------------------\n");
668 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
670 "(objectCategory=user)",
671 c
->opt_long_list_entries
? longattrs
:
672 shortattrs
, usergrp_display
,
675 return ADS_ERR_OK(rc
) ? 0 : -1;
678 return net_run_function(c
, argc
, argv
, "net ads user", func
);
681 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
683 return net_group_usage(c
, argc
, argv
);
686 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
690 LDAPMessage
*res
=NULL
;
694 if (argc
< 1 || c
->display_usage
) {
695 return net_ads_group_usage(c
, argc
, argv
);
698 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
702 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
704 if (!ADS_ERR_OK(status
)) {
705 d_fprintf(stderr
, "ads_group_add: %s\n", ads_errstr(status
));
709 if (ads_count_replies(ads
, res
)) {
710 d_fprintf(stderr
, "ads_group_add: Group %s already exists\n", argv
[0]);
714 if (c
->opt_container
) {
715 ou_str
= SMB_STRDUP(c
->opt_container
);
717 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
720 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
722 if (ADS_ERR_OK(status
)) {
723 d_printf("Group %s added\n", argv
[0]);
726 d_fprintf(stderr
, "Could not add group %s: %s\n", argv
[0],
732 ads_msgfree(ads
, res
);
738 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
742 LDAPMessage
*res
= NULL
;
745 if (argc
< 1 || c
->display_usage
) {
746 return net_ads_group_usage(c
, argc
, argv
);
749 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
753 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
754 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
755 d_printf("Group %s does not exist.\n", argv
[0]);
756 ads_msgfree(ads
, res
);
760 groupdn
= ads_get_dn(ads
, talloc_tos(), res
);
761 ads_msgfree(ads
, res
);
762 rc
= ads_del_dn(ads
, groupdn
);
763 TALLOC_FREE(groupdn
);
764 if (ADS_ERR_OK(rc
)) {
765 d_printf("Group %s deleted\n", argv
[0]);
769 d_fprintf(stderr
, "Error deleting group %s: %s\n", argv
[0],
775 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
777 struct functable func
[] = {
783 "net ads group add\n"
790 "Delete an AD group",
791 "net ads group delete\n"
792 " Delete an AD group"
794 {NULL
, NULL
, 0, NULL
, NULL
}
798 const char *shortattrs
[] = {"sAMAccountName", NULL
};
799 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
800 char *disp_fields
[2] = {NULL
, NULL
};
803 if (c
->display_usage
) {
804 d_printf("Usage:\n");
805 d_printf("net ads group\n"
806 " List AD groups\n");
807 net_display_usage_from_functable(func
);
811 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
815 if (c
->opt_long_list_entries
)
816 d_printf("\nGroup name Comment"
817 "\n-----------------------------\n");
818 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
820 "(objectCategory=group)",
821 c
->opt_long_list_entries
? longattrs
:
822 shortattrs
, usergrp_display
,
826 return ADS_ERR_OK(rc
) ? 0 : -1;
828 return net_run_function(c
, argc
, argv
, "net ads group", func
);
831 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
837 if (c
->display_usage
) {
840 " Display machine account details\n");
844 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
848 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
849 if (!ADS_ERR_OK(rc
)) {
850 d_fprintf(stderr
, "ads_find_machine_acct: %s\n", ads_errstr(rc
));
855 if (ads_count_replies(ads
, res
) == 0) {
856 d_fprintf(stderr
, "No machine account for '%s' found\n", global_myname());
866 /*******************************************************************
867 Leave an AD domain. Windows XP disables the machine account.
868 We'll try the same. The old code would do an LDAP delete.
869 That only worked using the machine creds because added the machine
870 with full control to the computer object's ACL.
871 *******************************************************************/
873 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
876 struct libnet_UnjoinCtx
*r
= NULL
;
879 if (c
->display_usage
) {
882 " Leave an AD domain\n");
887 d_fprintf(stderr
, "No realm set, are we joined ?\n");
891 if (!(ctx
= talloc_init("net_ads_leave"))) {
892 d_fprintf(stderr
, "Could not initialise talloc context.\n");
896 if (!c
->opt_kerberos
) {
897 use_in_memory_ccache();
900 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
901 if (!W_ERROR_IS_OK(werr
)) {
902 d_fprintf(stderr
, "Could not initialise unjoin context.\n");
907 r
->in
.use_kerberos
= c
->opt_kerberos
;
908 r
->in
.dc_name
= c
->opt_host
;
909 r
->in
.domain_name
= lp_realm();
910 r
->in
.admin_account
= c
->opt_user_name
;
911 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
912 r
->in
.modify_config
= lp_config_backend_is_registry();
914 /* Try to delete it, but if that fails, disable it. The
915 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
916 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
917 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
918 r
->in
.delete_machine_account
= true;
920 werr
= libnet_Unjoin(ctx
, r
);
921 if (!W_ERROR_IS_OK(werr
)) {
922 d_printf("Failed to leave domain: %s\n",
923 r
->out
.error_string
? r
->out
.error_string
:
924 get_friendly_werror_msg(werr
));
928 if (r
->out
.deleted_machine_account
) {
929 d_printf("Deleted account for '%s' in realm '%s'\n",
930 r
->in
.machine_name
, r
->out
.dns_domain_name
);
934 /* We couldn't delete it - see if the disable succeeded. */
935 if (r
->out
.disabled_machine_account
) {
936 d_printf("Disabled account for '%s' in realm '%s'\n",
937 r
->in
.machine_name
, r
->out
.dns_domain_name
);
942 /* Based on what we requseted, we shouldn't get here, but if
943 we did, it means the secrets were removed, and therefore
944 we have left the domain */
945 d_fprintf(stderr
, "Machine '%s' Left domain '%s'\n",
946 r
->in
.machine_name
, r
->out
.dns_domain_name
);
952 if (W_ERROR_IS_OK(werr
)) {
959 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
961 ADS_STRUCT
*ads
= NULL
;
964 if (!secrets_init()) {
965 DEBUG(1,("Failed to initialise secrets database\n"));
966 return NT_STATUS_ACCESS_DENIED
;
969 net_use_krb_machine_account(c
);
971 status
= ads_startup(c
, true, &ads
);
972 if (!ADS_ERR_OK(status
)) {
973 return ads_ntstatus(status
);
981 check that an existing join is OK
983 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
986 use_in_memory_ccache();
988 if (c
->display_usage
) {
991 " Test if the existing join is ok\n");
995 /* Display success or failure */
996 status
= net_ads_join_ok(c
);
997 if (!NT_STATUS_IS_OK(status
)) {
998 fprintf(stderr
,"Join to domain is not valid: %s\n",
999 get_friendly_nt_error_msg(status
));
1003 printf("Join is OK\n");
1007 /*******************************************************************
1008 Simple configu checks before beginning the join
1009 ********************************************************************/
1011 static WERROR
check_ads_config( void )
1013 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
1014 d_printf("Host is not configured as a member server.\n");
1015 return WERR_INVALID_DOMAIN_ROLE
;
1018 if (strlen(global_myname()) > 15) {
1019 d_printf("Our netbios name can be at most 15 chars long, "
1020 "\"%s\" is %u chars long\n", global_myname(),
1021 (unsigned int)strlen(global_myname()));
1022 return WERR_INVALID_COMPUTERNAME
;
1025 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1026 d_fprintf(stderr
, "realm must be set in in %s for ADS "
1027 "join to succeed.\n", get_dyn_CONFIGFILE());
1028 return WERR_INVALID_PARAM
;
1034 /*******************************************************************
1035 Send a DNS update request
1036 *******************************************************************/
1038 #if defined(WITH_DNS_UPDATES)
1040 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
1041 const char *pszDomainName
, const char *pszHostName
,
1042 const struct sockaddr_storage
*sslist
,
1045 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1046 const char *machine_name
,
1047 const struct sockaddr_storage
*addrs
,
1050 struct dns_rr_ns
*nameservers
= NULL
;
1052 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1055 const char *dnsdomain
= NULL
;
1056 char *root_domain
= NULL
;
1058 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1059 d_printf("No DNS domain configured for %s. "
1060 "Unable to perform DNS Update.\n", machine_name
);
1061 status
= NT_STATUS_INVALID_PARAMETER
;
1066 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
1067 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1068 /* Child domains often do not have NS records. Look
1069 for the NS record for the forest root domain
1070 (rootDomainNamingContext in therootDSE) */
1072 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1073 LDAPMessage
*msg
= NULL
;
1075 ADS_STATUS ads_status
;
1077 if ( !ads
->ldap
.ld
) {
1078 ads_status
= ads_connect( ads
);
1079 if ( !ADS_ERR_OK(ads_status
) ) {
1080 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1085 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1086 "(objectclass=*)", rootname_attrs
, &msg
);
1087 if (!ADS_ERR_OK(ads_status
)) {
1091 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1093 ads_msgfree( ads
, msg
);
1097 root_domain
= ads_build_domain( root_dn
);
1100 ads_msgfree( ads
, msg
);
1102 /* try again for NS servers */
1104 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1106 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1107 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1108 "realm\n", ads
->config
.realm
));
1112 dnsdomain
= root_domain
;
1116 /* Now perform the dns update - we'll try non-secure and if we fail,
1117 we'll follow it up with a secure update */
1119 fstrcpy( dns_server
, nameservers
[0].hostname
);
1121 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1122 if (!ERR_DNS_IS_OK(dns_err
)) {
1123 status
= NT_STATUS_UNSUCCESSFUL
;
1128 SAFE_FREE( root_domain
);
1133 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
)
1136 struct sockaddr_storage
*iplist
= NULL
;
1137 fstring machine_name
;
1140 name_to_fqdn( machine_name
, global_myname() );
1141 strlower_m( machine_name
);
1143 /* Get our ip address (not the 127.0.0.x address but a real ip
1146 num_addrs
= get_my_ip_address( &iplist
);
1147 if ( num_addrs
<= 0 ) {
1148 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1150 return NT_STATUS_INVALID_PARAMETER
;
1153 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1155 SAFE_FREE( iplist
);
1161 /*******************************************************************
1162 ********************************************************************/
1164 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1166 d_printf("net ads join [options]\n");
1167 d_printf("Valid options:\n");
1168 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1169 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1170 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1171 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1172 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1173 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1174 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1175 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1176 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1177 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1178 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1179 d_printf(" the two other attributes.\n");
1184 /*******************************************************************
1185 ********************************************************************/
1187 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1189 TALLOC_CTX
*ctx
= NULL
;
1190 struct libnet_JoinCtx
*r
= NULL
;
1191 const char *domain
= lp_realm();
1192 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1193 bool createupn
= false;
1194 const char *machineupn
= NULL
;
1195 const char *create_in_ou
= NULL
;
1197 const char *os_name
= NULL
;
1198 const char *os_version
= NULL
;
1199 bool modify_config
= lp_config_backend_is_registry();
1201 if (c
->display_usage
)
1202 return net_ads_join_usage(c
, argc
, argv
);
1204 if (!modify_config
) {
1206 werr
= check_ads_config();
1207 if (!W_ERROR_IS_OK(werr
)) {
1208 d_fprintf(stderr
, "Invalid configuration. Exiting....\n");
1213 if (!(ctx
= talloc_init("net_ads_join"))) {
1214 d_fprintf(stderr
, "Could not initialise talloc context.\n");
1219 if (!c
->opt_kerberos
) {
1220 use_in_memory_ccache();
1223 werr
= libnet_init_JoinCtx(ctx
, &r
);
1224 if (!W_ERROR_IS_OK(werr
)) {
1228 /* process additional command line args */
1230 for ( i
=0; i
<argc
; i
++ ) {
1231 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1233 machineupn
= get_string_param(argv
[i
]);
1235 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1236 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1237 d_fprintf(stderr
, "Please supply a valid OU path.\n");
1238 werr
= WERR_INVALID_PARAM
;
1242 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1243 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1244 d_fprintf(stderr
, "Please supply a operating system name.\n");
1245 werr
= WERR_INVALID_PARAM
;
1249 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1250 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1251 d_fprintf(stderr
, "Please supply a valid operating system version.\n");
1252 werr
= WERR_INVALID_PARAM
;
1262 d_fprintf(stderr
, "Please supply a valid domain name\n");
1263 werr
= WERR_INVALID_PARAM
;
1267 /* Do the domain join here */
1269 r
->in
.domain_name
= domain
;
1270 r
->in
.create_upn
= createupn
;
1271 r
->in
.upn
= machineupn
;
1272 r
->in
.account_ou
= create_in_ou
;
1273 r
->in
.os_name
= os_name
;
1274 r
->in
.os_version
= os_version
;
1275 r
->in
.dc_name
= c
->opt_host
;
1276 r
->in
.admin_account
= c
->opt_user_name
;
1277 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1279 r
->in
.use_kerberos
= c
->opt_kerberos
;
1280 r
->in
.modify_config
= modify_config
;
1281 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1282 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1283 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1285 werr
= libnet_Join(ctx
, r
);
1286 if (!W_ERROR_IS_OK(werr
)) {
1290 /* Check the short name of the domain */
1292 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1293 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1294 d_printf("domain name obtained from the server.\n");
1295 d_printf("Using the name [%s] from the server.\n", r
->out
.netbios_domain_name
);
1296 d_printf("You should set \"workgroup = %s\" in %s.\n",
1297 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1300 d_printf("Using short domain name -- %s\n", r
->out
.netbios_domain_name
);
1302 if (r
->out
.dns_domain_name
) {
1303 d_printf("Joined '%s' to realm '%s'\n", r
->in
.machine_name
,
1304 r
->out
.dns_domain_name
);
1306 d_printf("Joined '%s' to domain '%s'\n", r
->in
.machine_name
,
1307 r
->out
.netbios_domain_name
);
1310 #if defined(WITH_DNS_UPDATES)
1311 if (r
->out
.domain_is_ad
) {
1312 /* We enter this block with user creds */
1313 ADS_STRUCT
*ads_dns
= NULL
;
1315 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1316 /* kinit with the machine password */
1318 use_in_memory_ccache();
1319 if (asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname()) == -1) {
1322 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1323 r
->out
.netbios_domain_name
, NULL
, NULL
);
1324 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1325 strupper_m(ads_dns
->auth
.realm
);
1326 ads_kinit_password( ads_dns
);
1329 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns( ctx
, ads_dns
)) ) {
1330 d_fprintf( stderr
, "DNS update failed!\n" );
1333 /* exit from this block using machine creds */
1334 ads_destroy(&ads_dns
);
1343 /* issue an overall failure message at the end. */
1344 d_printf("Failed to join domain: %s\n",
1345 r
&& r
->out
.error_string
? r
->out
.error_string
:
1346 get_friendly_werror_msg(werr
));
1352 /*******************************************************************
1353 ********************************************************************/
1355 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1357 #if defined(WITH_DNS_UPDATES)
1363 talloc_enable_leak_report();
1366 if (argc
> 0 || c
->display_usage
) {
1368 "net ads dns register\n"
1369 " Register hostname with DNS\n");
1373 if (!(ctx
= talloc_init("net_ads_dns"))) {
1374 d_fprintf(stderr
, "Could not initialise talloc context\n");
1378 status
= ads_startup(c
, true, &ads
);
1379 if ( !ADS_ERR_OK(status
) ) {
1380 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1385 if ( !NT_STATUS_IS_OK(net_update_dns(ctx
, ads
)) ) {
1386 d_fprintf( stderr
, "DNS update failed!\n" );
1387 ads_destroy( &ads
);
1392 d_fprintf( stderr
, "Successfully registered hostname with DNS\n" );
1399 d_fprintf(stderr
, "DNS update support not enabled at compile time!\n");
1404 #if defined(WITH_DNS_UPDATES)
1405 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1408 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1410 #if defined(WITH_DNS_UPDATES)
1414 talloc_enable_leak_report();
1417 if (argc
!= 2 || c
->display_usage
) {
1419 "net ads dns gethostbyname <server> <name>\n"
1420 " Look up hostname from the AD\n"
1421 " server\tName server to use\n"
1422 " name\tName to look up\n");
1426 err
= do_gethostbyname(argv
[0], argv
[1]);
1428 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err
));
1433 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1435 struct functable func
[] = {
1438 net_ads_dns_register
,
1440 "Add host dns entry to AD",
1441 "net ads dns register\n"
1442 " Add host dns entry to AD"
1446 net_ads_dns_gethostbyname
,
1449 "net ads dns gethostbyname\n"
1452 {NULL
, NULL
, 0, NULL
, NULL
}
1455 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1458 /*******************************************************************
1459 ********************************************************************/
1461 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1464 "\nnet ads printer search <printer>"
1465 "\n\tsearch for a printer in the directory\n"
1466 "\nnet ads printer info <printer> <server>"
1467 "\n\tlookup info in directory for printer on server"
1468 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1469 "\nnet ads printer publish <printername>"
1470 "\n\tpublish printer in directory"
1471 "\n\t(note: printer name is required)\n"
1472 "\nnet ads printer remove <printername>"
1473 "\n\tremove printer from directory"
1474 "\n\t(note: printer name is required)\n");
1478 /*******************************************************************
1479 ********************************************************************/
1481 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1485 LDAPMessage
*res
= NULL
;
1487 if (c
->display_usage
) {
1489 "net ads printer search\n"
1490 " List printers in the AD\n");
1494 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1498 rc
= ads_find_printers(ads
, &res
);
1500 if (!ADS_ERR_OK(rc
)) {
1501 d_fprintf(stderr
, "ads_find_printer: %s\n", ads_errstr(rc
));
1502 ads_msgfree(ads
, res
);
1507 if (ads_count_replies(ads
, res
) == 0) {
1508 d_fprintf(stderr
, "No results found\n");
1509 ads_msgfree(ads
, res
);
1515 ads_msgfree(ads
, res
);
1520 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1524 const char *servername
, *printername
;
1525 LDAPMessage
*res
= NULL
;
1527 if (c
->display_usage
) {
1529 "net ads printer info [printername [servername]]\n"
1530 " Display printer info from AD\n"
1531 " printername\tPrinter name or wildcard\n"
1532 " servername\tName of the print server\n");
1536 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1541 printername
= argv
[0];
1547 servername
= argv
[1];
1549 servername
= global_myname();
1552 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1554 if (!ADS_ERR_OK(rc
)) {
1555 d_fprintf(stderr
, "Server '%s' not found: %s\n",
1556 servername
, ads_errstr(rc
));
1557 ads_msgfree(ads
, res
);
1562 if (ads_count_replies(ads
, res
) == 0) {
1563 d_fprintf(stderr
, "Printer '%s' not found\n", printername
);
1564 ads_msgfree(ads
, res
);
1570 ads_msgfree(ads
, res
);
1576 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1580 const char *servername
, *printername
;
1581 struct cli_state
*cli
;
1582 struct rpc_pipe_client
*pipe_hnd
;
1583 struct sockaddr_storage server_ss
;
1585 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1586 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1587 char *prt_dn
, *srv_dn
, **srv_cn
;
1588 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1589 LDAPMessage
*res
= NULL
;
1591 if (argc
< 1 || c
->display_usage
) {
1593 "net ads printer publish <printername> [servername]\n"
1594 " Publish printer in AD\n"
1595 " printername\tName of the printer\n"
1596 " servername\tName of the print server\n");
1597 talloc_destroy(mem_ctx
);
1601 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1602 talloc_destroy(mem_ctx
);
1606 printername
= argv
[0];
1609 servername
= argv
[1];
1611 servername
= global_myname();
1614 /* Get printer data from SPOOLSS */
1616 resolve_name(servername
, &server_ss
, 0x20);
1618 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1621 c
->opt_user_name
, c
->opt_workgroup
,
1622 c
->opt_password
? c
->opt_password
: "",
1623 CLI_FULL_CONNECTION_USE_KERBEROS
,
1626 if (NT_STATUS_IS_ERR(nt_status
)) {
1627 d_fprintf(stderr
, "Unable to open a connnection to %s to obtain data "
1628 "for %s\n", servername
, printername
);
1630 talloc_destroy(mem_ctx
);
1634 /* Publish on AD server */
1636 ads_find_machine_acct(ads
, &res
, servername
);
1638 if (ads_count_replies(ads
, res
) == 0) {
1639 d_fprintf(stderr
, "Could not find machine account for server %s\n",
1642 talloc_destroy(mem_ctx
);
1646 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1647 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1649 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1650 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1651 if (!srv_cn_escaped
|| !printername_escaped
) {
1652 SAFE_FREE(srv_cn_escaped
);
1653 SAFE_FREE(printername_escaped
);
1654 d_fprintf(stderr
, "Internal error, out of memory!");
1656 talloc_destroy(mem_ctx
);
1660 if (asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
) == -1) {
1661 SAFE_FREE(srv_cn_escaped
);
1662 SAFE_FREE(printername_escaped
);
1663 d_fprintf(stderr
, "Internal error, out of memory!");
1665 talloc_destroy(mem_ctx
);
1669 SAFE_FREE(srv_cn_escaped
);
1670 SAFE_FREE(printername_escaped
);
1672 nt_status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_spoolss
.syntax_id
, &pipe_hnd
);
1673 if (!NT_STATUS_IS_OK(nt_status
)) {
1674 d_fprintf(stderr
, "Unable to open a connnection to the spoolss pipe on %s\n",
1678 talloc_destroy(mem_ctx
);
1682 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1686 talloc_destroy(mem_ctx
);
1690 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1691 if (!ADS_ERR_OK(rc
)) {
1692 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1695 talloc_destroy(mem_ctx
);
1699 d_printf("published printer\n");
1702 talloc_destroy(mem_ctx
);
1707 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1711 const char *servername
;
1713 LDAPMessage
*res
= NULL
;
1715 if (argc
< 1 || c
->display_usage
) {
1717 "net ads printer remove <printername> [servername]\n"
1718 " Remove a printer from the AD\n"
1719 " printername\tName of the printer\n"
1720 " servername\tName of the print server\n");
1724 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1729 servername
= argv
[1];
1731 servername
= global_myname();
1734 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1736 if (!ADS_ERR_OK(rc
)) {
1737 d_fprintf(stderr
, "ads_find_printer_on_server: %s\n", ads_errstr(rc
));
1738 ads_msgfree(ads
, res
);
1743 if (ads_count_replies(ads
, res
) == 0) {
1744 d_fprintf(stderr
, "Printer '%s' not found\n", argv
[1]);
1745 ads_msgfree(ads
, res
);
1750 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
1751 ads_msgfree(ads
, res
);
1752 rc
= ads_del_dn(ads
, prt_dn
);
1753 TALLOC_FREE(prt_dn
);
1755 if (!ADS_ERR_OK(rc
)) {
1756 d_fprintf(stderr
, "ads_del_dn: %s\n", ads_errstr(rc
));
1765 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
1767 struct functable func
[] = {
1770 net_ads_printer_search
,
1772 "Search for a printer",
1773 "net ads printer search\n"
1774 " Search for a printer"
1778 net_ads_printer_info
,
1780 "Display printer information",
1781 "net ads printer info\n"
1782 " Display printer information"
1786 net_ads_printer_publish
,
1788 "Publish a printer",
1789 "net ads printer publish\n"
1790 " Publish a printer"
1794 net_ads_printer_remove
,
1797 "net ads printer remove\n"
1800 {NULL
, NULL
, 0, NULL
, NULL
}
1803 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
1807 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
1810 const char *auth_principal
= c
->opt_user_name
;
1811 const char *auth_password
= c
->opt_password
;
1813 char *new_password
= NULL
;
1818 if (c
->display_usage
) {
1820 "net ads password <username>\n"
1821 " Change password for user\n"
1822 " username\tName of user to change password for\n");
1826 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
1827 d_fprintf(stderr
, "You must supply an administrator username/password\n");
1832 d_fprintf(stderr
, "ERROR: You must say which username to change password for\n");
1837 if (!strchr_m(user
, '@')) {
1838 if (asprintf(&chr
, "%s@%s", argv
[0], lp_realm()) == -1) {
1844 use_in_memory_ccache();
1845 chr
= strchr_m(auth_principal
, '@');
1852 /* use the realm so we can eventually change passwords for users
1853 in realms other than default */
1854 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
1858 /* we don't actually need a full connect, but it's the easy way to
1859 fill in the KDC's addresss */
1862 if (!ads
->config
.realm
) {
1863 d_fprintf(stderr
, "Didn't find the kerberos server!\n");
1869 new_password
= (char *)argv
[1];
1871 if (asprintf(&prompt
, "Enter new password for %s:", user
) == -1) {
1874 new_password
= getpass(prompt
);
1878 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
1879 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
1880 if (!ADS_ERR_OK(ret
)) {
1881 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1886 d_printf("Password change for %s completed.\n", user
);
1892 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
1895 char *host_principal
;
1899 if (c
->display_usage
) {
1901 "net ads changetrustpw\n"
1902 " Change the machine account's trust password\n");
1906 if (!secrets_init()) {
1907 DEBUG(1,("Failed to initialise secrets database\n"));
1911 net_use_krb_machine_account(c
);
1913 use_in_memory_ccache();
1915 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1919 fstrcpy(my_name
, global_myname());
1920 strlower_m(my_name
);
1921 if (asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
) == -1) {
1925 d_printf("Changing password for principal: %s\n", host_principal
);
1927 ret
= ads_change_trust_account_password(ads
, host_principal
);
1929 if (!ADS_ERR_OK(ret
)) {
1930 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1932 SAFE_FREE(host_principal
);
1936 d_printf("Password change for principal %s succeeded.\n", host_principal
);
1938 if (USE_SYSTEM_KEYTAB
) {
1939 d_printf("Attempting to update system keytab with new password.\n");
1940 if (ads_keytab_create_default(ads
)) {
1941 d_printf("Failed to update system keytab.\n");
1946 SAFE_FREE(host_principal
);
1952 help for net ads search
1954 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
1957 "\nnet ads search <expression> <attributes...>\n"
1958 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1959 "The expression is a standard LDAP search expression, and the\n"
1960 "attributes are a list of LDAP fields to show in the results.\n\n"
1961 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1963 net_common_flags_usage(c
, argc
, argv
);
1969 general ADS search function. Useful in diagnosing problems in ADS
1971 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
1975 const char *ldap_exp
;
1977 LDAPMessage
*res
= NULL
;
1979 if (argc
< 1 || c
->display_usage
) {
1980 return net_ads_search_usage(c
, argc
, argv
);
1983 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1990 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
1992 ldap_exp
, attrs
, &res
);
1993 if (!ADS_ERR_OK(rc
)) {
1994 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
1999 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2001 /* dump the results */
2004 ads_msgfree(ads
, res
);
2012 help for net ads search
2014 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
2017 "\nnet ads dn <dn> <attributes...>\n"
2018 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2019 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2020 "to show in the results\n\n"
2021 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2022 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2024 net_common_flags_usage(c
, argc
, argv
);
2030 general ADS search function. Useful in diagnosing problems in ADS
2032 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
2038 LDAPMessage
*res
= NULL
;
2040 if (argc
< 1 || c
->display_usage
) {
2041 return net_ads_dn_usage(c
, argc
, argv
);
2044 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2051 rc
= ads_do_search_all(ads
, dn
,
2053 "(objectclass=*)", attrs
, &res
);
2054 if (!ADS_ERR_OK(rc
)) {
2055 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
2060 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2062 /* dump the results */
2065 ads_msgfree(ads
, res
);
2072 help for net ads sid search
2074 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2077 "\nnet ads sid <sid> <attributes...>\n"
2078 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2079 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2080 "to show in the results\n\n"
2081 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2083 net_common_flags_usage(c
, argc
, argv
);
2089 general ADS search function. Useful in diagnosing problems in ADS
2091 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2095 const char *sid_string
;
2097 LDAPMessage
*res
= NULL
;
2100 if (argc
< 1 || c
->display_usage
) {
2101 return net_ads_sid_usage(c
, argc
, argv
);
2104 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2108 sid_string
= argv
[0];
2111 if (!string_to_sid(&sid
, sid_string
)) {
2112 d_fprintf(stderr
, "could not convert sid\n");
2117 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2118 if (!ADS_ERR_OK(rc
)) {
2119 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
2124 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2126 /* dump the results */
2129 ads_msgfree(ads
, res
);
2135 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2140 if (c
->display_usage
) {
2142 "net ads keytab flush\n"
2143 " Delete the whole keytab\n");
2147 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2150 ret
= ads_keytab_flush(ads
);
2155 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2161 if (c
->display_usage
) {
2163 "net ads keytab add <principal> [principal ...]\n"
2164 " Add principals to local keytab\n"
2165 " principal\tKerberos principal to add to "
2170 d_printf("Processing principals to add...\n");
2171 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2174 for (i
= 0; i
< argc
; i
++) {
2175 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2181 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2186 if (c
->display_usage
) {
2188 "net ads keytab create\n"
2189 " Create new default keytab\n");
2193 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2196 ret
= ads_keytab_create_default(ads
);
2201 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2203 const char *keytab
= NULL
;
2205 if (c
->display_usage
) {
2207 "net ads keytab list [keytab]\n"
2208 " List a local keytab\n"
2209 " keytab\tKeytab to list\n");
2217 return ads_keytab_list(keytab
);
2221 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2223 struct functable func
[] = {
2228 "Add a service principal",
2229 "net ads keytab add\n"
2230 " Add a service principal"
2234 net_ads_keytab_create
,
2236 "Create a fresh keytab",
2237 "net ads keytab create\n"
2238 " Create a fresh keytab"
2242 net_ads_keytab_flush
,
2244 "Remove all keytab entries",
2245 "net ads keytab flush\n"
2246 " Remove all keytab entries"
2250 net_ads_keytab_list
,
2253 "net ads keytab list\n"
2256 {NULL
, NULL
, 0, NULL
, NULL
}
2259 if (!USE_KERBEROS_KEYTAB
) {
2260 d_printf("\nWarning: \"kerberos method\" must be set to a "
2261 "keytab method to use keytab functions.\n");
2264 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2267 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2271 if (c
->display_usage
) {
2273 "net ads kerberos renew\n"
2274 " Renew TGT from existing credential cache\n");
2278 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2280 d_printf("failed to renew kerberos ticket: %s\n",
2281 error_message(ret
));
2286 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2288 struct PAC_DATA
*pac
= NULL
;
2289 struct PAC_LOGON_INFO
*info
= NULL
;
2290 TALLOC_CTX
*mem_ctx
= NULL
;
2294 if (c
->display_usage
) {
2296 "net ads kerberos pac\n"
2297 " Dump the Kerberos PAC\n");
2301 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2306 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2308 status
= kerberos_return_pac(mem_ctx
,
2317 2592000, /* one month */
2319 if (!NT_STATUS_IS_OK(status
)) {
2320 d_printf("failed to query kerberos PAC: %s\n",
2325 info
= get_logon_info_from_pac(pac
);
2328 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2329 d_printf("The Pac: %s\n", s
);
2334 TALLOC_FREE(mem_ctx
);
2338 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2340 TALLOC_CTX
*mem_ctx
= NULL
;
2344 if (c
->display_usage
) {
2346 "net ads kerberos kinit\n"
2347 " Get Ticket Granting Ticket (TGT) for the user\n");
2351 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2356 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2358 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2366 2592000, /* one month */
2369 d_printf("failed to kinit password: %s\n",
2376 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2378 struct functable func
[] = {
2381 net_ads_kerberos_kinit
,
2383 "Retrieve Ticket Granting Ticket (TGT)",
2384 "net ads kerberos kinit\n"
2385 " Receive Ticket Granting Ticket (TGT)"
2389 net_ads_kerberos_renew
,
2391 "Renew Ticket Granting Ticket from credential cache"
2392 "net ads kerberos renew\n"
2393 " Renew Ticket Granting Ticket from credential cache"
2397 net_ads_kerberos_pac
,
2399 "Dump Kerberos PAC",
2400 "net ads kerberos pac\n"
2401 " Dump Kerberos PAC"
2403 {NULL
, NULL
, 0, NULL
, NULL
}
2406 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2409 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2411 struct functable func
[] = {
2416 "Display details on remote ADS server",
2418 " Display details on remote ADS server"
2424 "Join the local machine to ADS realm",
2426 " Join the local machine to ADS realm"
2432 "Validate machine account",
2433 "net ads testjoin\n"
2434 " Validate machine account"
2440 "Remove the local machine from ADS",
2442 " Remove the local machine from ADS"
2448 "Display machine account details",
2450 " Display machine account details"
2456 "List/modify users",
2458 " List/modify users"
2464 "List/modify groups",
2466 " List/modify groups"
2472 "Issue dynamic DNS update",
2474 " Issue dynamic DNS update"
2480 "Change user passwords",
2481 "net ads password\n"
2482 " Change user passwords"
2486 net_ads_changetrustpw
,
2488 "Change trust account password",
2489 "net ads changetrustpw\n"
2490 " Change trust account password"
2496 "List/modify printer entries",
2498 " List/modify printer entries"
2504 "Issue LDAP search using filter",
2506 " Issue LDAP search using filter"
2512 "Issue LDAP search by DN",
2514 " Issue LDAP search by DN"
2520 "Issue LDAP search by SID",
2522 " Issue LDAP search by SID"
2528 "Display workgroup name",
2529 "net ads workgroup\n"
2530 " Display the workgroup name"
2536 "Perfom CLDAP query on DC",
2538 " Find the ADS DC using CLDAP lookups"
2544 "Manage local keytab file",
2546 " Manage local keytab file"
2552 "Manage group policy objects",
2554 " Manage group policy objects"
2560 "Manage kerberos keytab",
2561 "net ads kerberos\n"
2562 " Manage kerberos keytab"
2564 {NULL
, NULL
, 0, NULL
, NULL
}
2567 return net_run_function(c
, argc
, argv
, "net ads", func
);
2572 static int net_ads_noads(void)
2574 d_fprintf(stderr
, "ADS support not compiled in\n");
2578 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2580 return net_ads_noads();
2583 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2585 return net_ads_noads();
2588 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2590 return net_ads_noads();
2593 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2595 return net_ads_noads();
2598 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2600 return net_ads_noads();
2603 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2605 return net_ads_noads();
2608 /* this one shouldn't display a message */
2609 int net_ads_check(struct net_context
*c
)
2614 int net_ads_check_our_domain(struct net_context
*c
)
2619 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2621 return net_ads_noads();
2624 #endif /* WITH_ADS */