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"
28 /* when we do not have sufficient input parameters to contact a remote domain
29 * we always fall back to our own realm - Guenther*/
31 static const char *assume_own_realm(struct net_context
*c
)
33 if (!c
->opt_host
&& strequal(lp_workgroup(), c
->opt_target_workgroup
)) {
41 do a cldap netlogon query
43 static int net_ads_cldap_netlogon(struct net_context
*c
, ADS_STRUCT
*ads
)
45 char addr
[INET6_ADDRSTRLEN
];
46 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
48 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
49 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
50 d_fprintf(stderr
, "CLDAP query failed!\n");
54 d_printf("Information for Domain Controller: %s\n\n",
57 d_printf("Response Type: ");
58 switch (reply
.command
) {
59 case LOGON_SAM_LOGON_USER_UNKNOWN_EX
:
60 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
62 case LOGON_SAM_LOGON_RESPONSE_EX
:
63 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
66 d_printf("0x%x\n", reply
.command
);
70 d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), reply
.domain_uuid
));
74 "\tIs a GC of the forest: %s\n"
75 "\tIs an LDAP server: %s\n"
77 "\tIs running a KDC: %s\n"
78 "\tIs running time services: %s\n"
79 "\tIs the closest DC: %s\n"
81 "\tHas a hardware clock: %s\n"
82 "\tIs a non-domain NC serviced by LDAP server: %s\n"
83 "\tIs NT6 DC that has some secrets: %s\n"
84 "\tIs NT6 DC that has all secrets: %s\n",
85 (reply
.server_type
& NBT_SERVER_PDC
) ? "yes" : "no",
86 (reply
.server_type
& NBT_SERVER_GC
) ? "yes" : "no",
87 (reply
.server_type
& NBT_SERVER_LDAP
) ? "yes" : "no",
88 (reply
.server_type
& NBT_SERVER_DS
) ? "yes" : "no",
89 (reply
.server_type
& NBT_SERVER_KDC
) ? "yes" : "no",
90 (reply
.server_type
& NBT_SERVER_TIMESERV
) ? "yes" : "no",
91 (reply
.server_type
& NBT_SERVER_CLOSEST
) ? "yes" : "no",
92 (reply
.server_type
& NBT_SERVER_WRITABLE
) ? "yes" : "no",
93 (reply
.server_type
& NBT_SERVER_GOOD_TIMESERV
) ? "yes" : "no",
94 (reply
.server_type
& NBT_SERVER_NDNC
) ? "yes" : "no",
95 (reply
.server_type
& NBT_SERVER_SELECT_SECRET_DOMAIN_6
) ? "yes" : "no",
96 (reply
.server_type
& NBT_SERVER_FULL_SECRET_DOMAIN_6
) ? "yes" : "no");
99 printf("Forest:\t\t\t%s\n", reply
.forest
);
100 printf("Domain:\t\t\t%s\n", reply
.dns_domain
);
101 printf("Domain Controller:\t%s\n", reply
.pdc_dns_name
);
103 printf("Pre-Win2k Domain:\t%s\n", reply
.domain
);
104 printf("Pre-Win2k Hostname:\t%s\n", reply
.pdc_name
);
106 if (*reply
.user_name
) printf("User name:\t%s\n", reply
.user_name
);
108 printf("Server Site Name :\t\t%s\n", reply
.server_site
);
109 printf("Client Site Name :\t\t%s\n", reply
.client_site
);
111 d_printf("NT Version: %d\n", reply
.nt_version
);
112 d_printf("LMNT Token: %.2x\n", reply
.lmnt_token
);
113 d_printf("LM20 Token: %.2x\n", reply
.lm20_token
);
119 this implements the CLDAP based netlogon lookup requests
120 for finding the domain controller of a ADS domain
122 static int net_ads_lookup(struct net_context
*c
, int argc
, const char **argv
)
126 if (c
->display_usage
) {
129 " Find the ADS DC using CLDAP lookup.\n");
133 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
134 d_fprintf(stderr
, "Didn't find the cldap server!\n");
138 if (!ads
->config
.realm
) {
139 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
140 ads
->ldap
.port
= 389;
143 return net_ads_cldap_netlogon(c
, ads
);
148 static int net_ads_info(struct net_context
*c
, int argc
, const char **argv
)
151 char addr
[INET6_ADDRSTRLEN
];
153 if (c
->display_usage
) {
156 " Display information about an Active Directory "
161 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
162 d_fprintf(stderr
, "Didn't find the ldap server!\n");
166 if (!ads
|| !ads
->config
.realm
) {
167 d_fprintf(stderr
, "Didn't find the ldap server!\n");
171 /* Try to set the server's current time since we didn't do a full
172 TCP LDAP session initially */
174 if ( !ADS_ERR_OK(ads_current_time( ads
)) ) {
175 d_fprintf( stderr
, "Failed to get server's current time!\n");
178 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
180 d_printf("LDAP server: %s\n", addr
);
181 d_printf("LDAP server name: %s\n", ads
->config
.ldap_server_name
);
182 d_printf("Realm: %s\n", ads
->config
.realm
);
183 d_printf("Bind Path: %s\n", ads
->config
.bind_path
);
184 d_printf("LDAP port: %d\n", ads
->ldap
.port
);
185 d_printf("Server time: %s\n", http_timestring(ads
->config
.current_time
));
187 d_printf("KDC server: %s\n", ads
->auth
.kdc_server
);
188 d_printf("Server time offset: %d\n", ads
->auth
.time_offset
);
193 static void use_in_memory_ccache(void) {
194 /* Use in-memory credentials cache so we do not interfere with
195 * existing credentials */
196 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
199 static ADS_STATUS
ads_startup_int(struct net_context
*c
, bool only_own_domain
,
200 uint32 auth_flags
, ADS_STRUCT
**ads_ret
)
202 ADS_STRUCT
*ads
= NULL
;
204 bool need_password
= false;
205 bool second_time
= false;
207 const char *realm
= NULL
;
208 bool tried_closest_dc
= false;
210 /* lp_realm() should be handled by a command line param,
211 However, the join requires that realm be set in smb.conf
212 and compares our realm with the remote server's so this is
213 ok until someone needs more flexibility */
218 if (only_own_domain
) {
221 realm
= assume_own_realm(c
);
224 ads
= ads_init(realm
, c
->opt_target_workgroup
, c
->opt_host
);
226 if (!c
->opt_user_name
) {
227 c
->opt_user_name
= "administrator";
230 if (c
->opt_user_specified
) {
231 need_password
= true;
235 if (!c
->opt_password
&& need_password
&& !c
->opt_machine_pass
) {
236 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
237 if (!c
->opt_password
) {
239 return ADS_ERROR(LDAP_NO_MEMORY
);
243 if (c
->opt_password
) {
244 use_in_memory_ccache();
245 SAFE_FREE(ads
->auth
.password
);
246 ads
->auth
.password
= smb_xstrdup(c
->opt_password
);
249 ads
->auth
.flags
|= auth_flags
;
250 SAFE_FREE(ads
->auth
.user_name
);
251 ads
->auth
.user_name
= smb_xstrdup(c
->opt_user_name
);
254 * If the username is of the form "name@realm",
255 * extract the realm and convert to upper case.
256 * This is only used to establish the connection.
258 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
260 SAFE_FREE(ads
->auth
.realm
);
261 ads
->auth
.realm
= smb_xstrdup(cp
);
262 strupper_m(ads
->auth
.realm
);
265 status
= ads_connect(ads
);
267 if (!ADS_ERR_OK(status
)) {
269 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
270 NT_STATUS_NO_LOGON_SERVERS
)) {
271 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
276 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
277 need_password
= true;
286 /* when contacting our own domain, make sure we use the closest DC.
287 * This is done by reconnecting to ADS because only the first call to
288 * ads_connect will give us our own sitename */
290 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
292 tried_closest_dc
= true; /* avoid loop */
294 if (!ads_closest_dc(ads
)) {
296 namecache_delete(ads
->server
.realm
, 0x1C);
297 namecache_delete(ads
->server
.workgroup
, 0x1C);
310 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
312 return ads_startup_int(c
, only_own_domain
, 0, ads
);
315 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
317 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
321 Check to see if connection can be made via ads.
322 ads_startup() stores the password in opt_password if it needs to so
323 that rpc or rap can use it without re-prompting.
325 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
330 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
334 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
336 status
= ads_connect(ads
);
337 if ( !ADS_ERR_OK(status
) ) {
345 int net_ads_check_our_domain(struct net_context
*c
)
347 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
350 int net_ads_check(struct net_context
*c
)
352 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
356 determine the netbios workgroup name for a domain
358 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
361 char addr
[INET6_ADDRSTRLEN
];
362 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
364 if (c
->display_usage
) {
366 "net ads workgroup\n"
367 " Print the workgroup name\n");
371 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
372 d_fprintf(stderr
, "Didn't find the cldap server!\n");
376 if (!ads
->config
.realm
) {
377 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
378 ads
->ldap
.port
= 389;
381 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
382 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
383 d_fprintf(stderr
, "CLDAP query failed!\n");
387 d_printf("Workgroup: %s\n", reply
.domain
);
396 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
398 char **disp_fields
= (char **) data_area
;
400 if (!field
) { /* must be end of record */
401 if (disp_fields
[0]) {
402 if (!strchr_m(disp_fields
[0], '$')) {
404 d_printf("%-21.21s %s\n",
405 disp_fields
[0], disp_fields
[1]);
407 d_printf("%s\n", disp_fields
[0]);
410 SAFE_FREE(disp_fields
[0]);
411 SAFE_FREE(disp_fields
[1]);
414 if (!values
) /* must be new field, indicate string field */
416 if (StrCaseCmp(field
, "sAMAccountName") == 0) {
417 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
419 if (StrCaseCmp(field
, "description") == 0)
420 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
424 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
426 return net_user_usage(c
, argc
, argv
);
429 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
434 LDAPMessage
*res
=NULL
;
438 if (argc
< 1 || c
->display_usage
)
439 return net_ads_user_usage(c
, argc
, argv
);
441 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
445 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
447 if (!ADS_ERR_OK(status
)) {
448 d_fprintf(stderr
, "ads_user_add: %s\n", ads_errstr(status
));
452 if (ads_count_replies(ads
, res
)) {
453 d_fprintf(stderr
, "ads_user_add: User %s already exists\n", argv
[0]);
457 if (c
->opt_container
) {
458 ou_str
= SMB_STRDUP(c
->opt_container
);
460 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
463 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
465 if (!ADS_ERR_OK(status
)) {
466 d_fprintf(stderr
, "Could not add user %s: %s\n", argv
[0],
471 /* if no password is to be set, we're done */
473 d_printf("User %s added\n", argv
[0]);
478 /* try setting the password */
479 if (asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
) == -1) {
482 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
483 ads
->auth
.time_offset
);
485 if (ADS_ERR_OK(status
)) {
486 d_printf("User %s added\n", argv
[0]);
491 /* password didn't set, delete account */
492 d_fprintf(stderr
, "Could not add user %s. Error setting password %s\n",
493 argv
[0], ads_errstr(status
));
494 ads_msgfree(ads
, res
);
495 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
496 if (ADS_ERR_OK(status
)) {
497 userdn
= ads_get_dn(ads
, res
);
498 ads_del_dn(ads
, userdn
);
499 ads_memfree(ads
, userdn
);
504 ads_msgfree(ads
, res
);
510 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
515 const char *attrs
[] = {"memberOf", NULL
};
516 char *searchstring
=NULL
;
520 if (argc
< 1 || c
->display_usage
) {
521 return net_ads_user_usage(c
, argc
, argv
);
524 escaped_user
= escape_ldap_string_alloc(argv
[0]);
527 d_fprintf(stderr
, "ads_user_info: failed to escape user %s\n", argv
[0]);
531 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
532 SAFE_FREE(escaped_user
);
536 if (asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
) == -1) {
537 SAFE_FREE(escaped_user
);
540 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
541 safe_free(searchstring
);
543 if (!ADS_ERR_OK(rc
)) {
544 d_fprintf(stderr
, "ads_search: %s\n", ads_errstr(rc
));
546 SAFE_FREE(escaped_user
);
550 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
551 (LDAPMessage
*)res
, "memberOf");
556 for (i
=0;grouplist
[i
];i
++) {
557 groupname
= ldap_explode_dn(grouplist
[i
], 1);
558 d_printf("%s\n", groupname
[0]);
559 ldap_value_free(groupname
);
561 ldap_value_free(grouplist
);
564 ads_msgfree(ads
, res
);
566 SAFE_FREE(escaped_user
);
570 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
574 LDAPMessage
*res
= NULL
;
578 return net_ads_user_usage(c
, argc
, argv
);
581 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
585 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
586 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
587 d_printf("User %s does not exist.\n", argv
[0]);
588 ads_msgfree(ads
, res
);
592 userdn
= ads_get_dn(ads
, res
);
593 ads_msgfree(ads
, res
);
594 rc
= ads_del_dn(ads
, userdn
);
595 ads_memfree(ads
, userdn
);
596 if (ADS_ERR_OK(rc
)) {
597 d_printf("User %s deleted\n", argv
[0]);
601 d_fprintf(stderr
, "Error deleting user %s: %s\n", argv
[0],
607 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
609 struct functable func
[] = {
622 "Display information about an AD user",
623 "net ads user info\n"
624 " Display information about an AD user"
631 "net ads user delete\n"
634 {NULL
, NULL
, 0, NULL
, NULL
}
638 const char *shortattrs
[] = {"sAMAccountName", NULL
};
639 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
640 char *disp_fields
[2] = {NULL
, NULL
};
643 if (c
->display_usage
) {
644 d_printf("Usage:\n");
645 d_printf("net ads user\n"
647 net_display_usage_from_functable(func
);
651 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
655 if (c
->opt_long_list_entries
)
656 d_printf("\nUser name Comment"
657 "\n-----------------------------\n");
659 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
661 "(objectCategory=user)",
662 c
->opt_long_list_entries
? longattrs
:
663 shortattrs
, usergrp_display
,
666 return ADS_ERR_OK(rc
) ? 0 : -1;
669 return net_run_function(c
, argc
, argv
, "net ads user", func
);
672 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
674 return net_group_usage(c
, argc
, argv
);
677 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
681 LDAPMessage
*res
=NULL
;
685 if (argc
< 1 || c
->display_usage
) {
686 return net_ads_group_usage(c
, argc
, argv
);
689 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
693 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
695 if (!ADS_ERR_OK(status
)) {
696 d_fprintf(stderr
, "ads_group_add: %s\n", ads_errstr(status
));
700 if (ads_count_replies(ads
, res
)) {
701 d_fprintf(stderr
, "ads_group_add: Group %s already exists\n", argv
[0]);
705 if (c
->opt_container
) {
706 ou_str
= SMB_STRDUP(c
->opt_container
);
708 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
711 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
713 if (ADS_ERR_OK(status
)) {
714 d_printf("Group %s added\n", argv
[0]);
717 d_fprintf(stderr
, "Could not add group %s: %s\n", argv
[0],
723 ads_msgfree(ads
, res
);
729 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
733 LDAPMessage
*res
= NULL
;
736 if (argc
< 1 || c
->display_usage
) {
737 return net_ads_group_usage(c
, argc
, argv
);
740 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
744 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
745 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
746 d_printf("Group %s does not exist.\n", argv
[0]);
747 ads_msgfree(ads
, res
);
751 groupdn
= ads_get_dn(ads
, res
);
752 ads_msgfree(ads
, res
);
753 rc
= ads_del_dn(ads
, groupdn
);
754 ads_memfree(ads
, groupdn
);
755 if (ADS_ERR_OK(rc
)) {
756 d_printf("Group %s deleted\n", argv
[0]);
760 d_fprintf(stderr
, "Error deleting group %s: %s\n", argv
[0],
766 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
768 struct functable func
[] = {
774 "net ads group add\n"
781 "Delete an AD group",
782 "net ads group delete\n"
783 " Delete an AD group"
785 {NULL
, NULL
, 0, NULL
, NULL
}
789 const char *shortattrs
[] = {"sAMAccountName", NULL
};
790 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
791 char *disp_fields
[2] = {NULL
, NULL
};
794 if (c
->display_usage
) {
795 d_printf("Usage:\n");
796 d_printf("net ads group\n"
797 " List AD groups\n");
798 net_display_usage_from_functable(func
);
802 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
806 if (c
->opt_long_list_entries
)
807 d_printf("\nGroup name Comment"
808 "\n-----------------------------\n");
809 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
811 "(objectCategory=group)",
812 c
->opt_long_list_entries
? longattrs
:
813 shortattrs
, usergrp_display
,
817 return ADS_ERR_OK(rc
) ? 0 : -1;
819 return net_run_function(c
, argc
, argv
, "net ads group", func
);
822 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
828 if (c
->display_usage
) {
831 " Display machine account details\n");
835 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
839 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
840 if (!ADS_ERR_OK(rc
)) {
841 d_fprintf(stderr
, "ads_find_machine_acct: %s\n", ads_errstr(rc
));
846 if (ads_count_replies(ads
, res
) == 0) {
847 d_fprintf(stderr
, "No machine account for '%s' found\n", global_myname());
857 /*******************************************************************
858 Leave an AD domain. Windows XP disables the machine account.
859 We'll try the same. The old code would do an LDAP delete.
860 That only worked using the machine creds because added the machine
861 with full control to the computer object's ACL.
862 *******************************************************************/
864 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
867 struct libnet_UnjoinCtx
*r
= NULL
;
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 (!c
->opt_kerberos
) {
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");
898 r
->in
.use_kerberos
= c
->opt_kerberos
;
899 r
->in
.dc_name
= c
->opt_host
;
900 r
->in
.domain_name
= lp_realm();
901 r
->in
.admin_account
= c
->opt_user_name
;
902 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
903 r
->in
.modify_config
= lp_config_backend_is_registry();
904 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
905 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
907 werr
= libnet_Unjoin(ctx
, r
);
908 if (!W_ERROR_IS_OK(werr
)) {
909 d_printf("Failed to leave domain: %s\n",
910 r
->out
.error_string
? r
->out
.error_string
:
911 get_friendly_werror_msg(werr
));
915 if (W_ERROR_IS_OK(werr
)) {
916 d_printf("Deleted account for '%s' in realm '%s'\n",
917 r
->in
.machine_name
, r
->out
.dns_domain_name
);
921 /* We couldn't delete it - see if the disable succeeded. */
922 if (r
->out
.disabled_machine_account
) {
923 d_printf("Disabled account for '%s' in realm '%s'\n",
924 r
->in
.machine_name
, r
->out
.dns_domain_name
);
929 d_fprintf(stderr
, "Failed to disable machine account for '%s' in realm '%s'\n",
930 r
->in
.machine_name
, r
->out
.dns_domain_name
);
936 if (W_ERROR_IS_OK(werr
)) {
943 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
945 ADS_STRUCT
*ads
= NULL
;
948 if (!secrets_init()) {
949 DEBUG(1,("Failed to initialise secrets database\n"));
950 return NT_STATUS_ACCESS_DENIED
;
953 net_use_krb_machine_account(c
);
955 status
= ads_startup(c
, true, &ads
);
956 if (!ADS_ERR_OK(status
)) {
957 return ads_ntstatus(status
);
965 check that an existing join is OK
967 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
970 use_in_memory_ccache();
972 if (c
->display_usage
) {
975 " Test if the existing join is ok\n");
979 /* Display success or failure */
980 status
= net_ads_join_ok(c
);
981 if (!NT_STATUS_IS_OK(status
)) {
982 fprintf(stderr
,"Join to domain is not valid: %s\n",
983 get_friendly_nt_error_msg(status
));
987 printf("Join is OK\n");
991 /*******************************************************************
992 Simple configu checks before beginning the join
993 ********************************************************************/
995 static WERROR
check_ads_config( void )
997 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
998 d_printf("Host is not configured as a member server.\n");
999 return WERR_INVALID_DOMAIN_ROLE
;
1002 if (strlen(global_myname()) > 15) {
1003 d_printf("Our netbios name can be at most 15 chars long, "
1004 "\"%s\" is %u chars long\n", global_myname(),
1005 (unsigned int)strlen(global_myname()));
1006 return WERR_INVALID_COMPUTER_NAME
;
1009 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1010 d_fprintf(stderr
, "realm must be set in in %s for ADS "
1011 "join to succeed.\n", get_dyn_CONFIGFILE());
1012 return WERR_INVALID_PARAM
;
1018 /*******************************************************************
1019 Send a DNS update request
1020 *******************************************************************/
1022 #if defined(WITH_DNS_UPDATES)
1024 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
1025 const char *pszDomainName
, const char *pszHostName
,
1026 const struct sockaddr_storage
*sslist
,
1029 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1030 const char *machine_name
,
1031 const struct sockaddr_storage
*addrs
,
1034 struct dns_rr_ns
*nameservers
= NULL
;
1036 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1039 const char *dnsdomain
= NULL
;
1040 char *root_domain
= NULL
;
1042 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1043 d_printf("No DNS domain configured for %s. "
1044 "Unable to perform DNS Update.\n", machine_name
);
1045 status
= NT_STATUS_INVALID_PARAMETER
;
1050 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
1051 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1052 /* Child domains often do not have NS records. Look
1053 for the NS record for the forest root domain
1054 (rootDomainNamingContext in therootDSE) */
1056 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1057 LDAPMessage
*msg
= NULL
;
1059 ADS_STATUS ads_status
;
1061 if ( !ads
->ldap
.ld
) {
1062 ads_status
= ads_connect( ads
);
1063 if ( !ADS_ERR_OK(ads_status
) ) {
1064 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1069 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1070 "(objectclass=*)", rootname_attrs
, &msg
);
1071 if (!ADS_ERR_OK(ads_status
)) {
1075 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1077 ads_msgfree( ads
, msg
);
1081 root_domain
= ads_build_domain( root_dn
);
1084 ads_msgfree( ads
, msg
);
1086 /* try again for NS servers */
1088 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1090 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1091 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1092 "realm\n", ads
->config
.realm
));
1096 dnsdomain
= root_domain
;
1100 /* Now perform the dns update - we'll try non-secure and if we fail,
1101 we'll follow it up with a secure update */
1103 fstrcpy( dns_server
, nameservers
[0].hostname
);
1105 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1106 if (!ERR_DNS_IS_OK(dns_err
)) {
1107 status
= NT_STATUS_UNSUCCESSFUL
;
1112 SAFE_FREE( root_domain
);
1117 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
)
1120 struct sockaddr_storage
*iplist
= NULL
;
1121 fstring machine_name
;
1124 name_to_fqdn( machine_name
, global_myname() );
1125 strlower_m( machine_name
);
1127 /* Get our ip address (not the 127.0.0.x address but a real ip
1130 num_addrs
= get_my_ip_address( &iplist
);
1131 if ( num_addrs
<= 0 ) {
1132 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1134 return NT_STATUS_INVALID_PARAMETER
;
1137 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1139 SAFE_FREE( iplist
);
1145 /*******************************************************************
1146 ********************************************************************/
1148 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1150 d_printf("net ads join [options]\n");
1151 d_printf("Valid options:\n");
1152 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1153 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1154 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1155 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1156 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1157 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1158 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1159 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1160 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1161 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1162 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1163 d_printf(" the two other attributes.\n");
1168 /*******************************************************************
1169 ********************************************************************/
1171 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1173 TALLOC_CTX
*ctx
= NULL
;
1174 struct libnet_JoinCtx
*r
= NULL
;
1175 const char *domain
= lp_realm();
1176 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1177 bool createupn
= false;
1178 const char *machineupn
= NULL
;
1179 const char *create_in_ou
= NULL
;
1181 const char *os_name
= NULL
;
1182 const char *os_version
= NULL
;
1183 bool modify_config
= lp_config_backend_is_registry();
1185 if (c
->display_usage
)
1186 return net_ads_join_usage(c
, argc
, argv
);
1188 if (!modify_config
) {
1190 werr
= check_ads_config();
1191 if (!W_ERROR_IS_OK(werr
)) {
1192 d_fprintf(stderr
, "Invalid configuration. Exiting....\n");
1197 if (!(ctx
= talloc_init("net_ads_join"))) {
1198 d_fprintf(stderr
, "Could not initialise talloc context.\n");
1203 if (!c
->opt_kerberos
) {
1204 use_in_memory_ccache();
1207 werr
= libnet_init_JoinCtx(ctx
, &r
);
1208 if (!W_ERROR_IS_OK(werr
)) {
1212 /* process additional command line args */
1214 for ( i
=0; i
<argc
; i
++ ) {
1215 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1217 machineupn
= get_string_param(argv
[i
]);
1219 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1220 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1221 d_fprintf(stderr
, "Please supply a valid OU path.\n");
1222 werr
= WERR_INVALID_PARAM
;
1226 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1227 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1228 d_fprintf(stderr
, "Please supply a operating system name.\n");
1229 werr
= WERR_INVALID_PARAM
;
1233 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1234 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1235 d_fprintf(stderr
, "Please supply a valid operating system version.\n");
1236 werr
= WERR_INVALID_PARAM
;
1246 d_fprintf(stderr
, "Please supply a valid domain name\n");
1247 werr
= WERR_INVALID_PARAM
;
1251 /* Do the domain join here */
1253 r
->in
.domain_name
= domain
;
1254 r
->in
.create_upn
= createupn
;
1255 r
->in
.upn
= machineupn
;
1256 r
->in
.account_ou
= create_in_ou
;
1257 r
->in
.os_name
= os_name
;
1258 r
->in
.os_version
= os_version
;
1259 r
->in
.dc_name
= c
->opt_host
;
1260 r
->in
.admin_account
= c
->opt_user_name
;
1261 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1263 r
->in
.use_kerberos
= c
->opt_kerberos
;
1264 r
->in
.modify_config
= modify_config
;
1265 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1266 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1267 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1269 werr
= libnet_Join(ctx
, r
);
1270 if (!W_ERROR_IS_OK(werr
)) {
1274 /* Check the short name of the domain */
1276 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1277 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1278 d_printf("domain name obtained from the server.\n");
1279 d_printf("Using the name [%s] from the server.\n", r
->out
.netbios_domain_name
);
1280 d_printf("You should set \"workgroup = %s\" in %s.\n",
1281 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1284 d_printf("Using short domain name -- %s\n", r
->out
.netbios_domain_name
);
1286 if (r
->out
.dns_domain_name
) {
1287 d_printf("Joined '%s' to realm '%s'\n", r
->in
.machine_name
,
1288 r
->out
.dns_domain_name
);
1290 d_printf("Joined '%s' to domain '%s'\n", r
->in
.machine_name
,
1291 r
->out
.netbios_domain_name
);
1294 #if defined(WITH_DNS_UPDATES)
1295 if (r
->out
.domain_is_ad
) {
1296 /* We enter this block with user creds */
1297 ADS_STRUCT
*ads_dns
= NULL
;
1299 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1300 /* kinit with the machine password */
1302 use_in_memory_ccache();
1303 if (asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname()) == -1) {
1306 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1307 r
->out
.netbios_domain_name
, NULL
, NULL
);
1308 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1309 strupper_m(ads_dns
->auth
.realm
);
1310 ads_kinit_password( ads_dns
);
1313 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns( ctx
, ads_dns
)) ) {
1314 d_fprintf( stderr
, "DNS update failed!\n" );
1317 /* exit from this block using machine creds */
1318 ads_destroy(&ads_dns
);
1327 /* issue an overall failure message at the end. */
1328 d_printf("Failed to join domain: %s\n",
1329 r
&& r
->out
.error_string
? r
->out
.error_string
:
1330 get_friendly_werror_msg(werr
));
1336 /*******************************************************************
1337 ********************************************************************/
1339 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1341 #if defined(WITH_DNS_UPDATES)
1347 talloc_enable_leak_report();
1350 if (argc
> 0 || c
->display_usage
) {
1352 "net ads dns register\n"
1353 " Register hostname with DNS\n");
1357 if (!(ctx
= talloc_init("net_ads_dns"))) {
1358 d_fprintf(stderr
, "Could not initialise talloc context\n");
1362 status
= ads_startup(c
, true, &ads
);
1363 if ( !ADS_ERR_OK(status
) ) {
1364 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1369 if ( !NT_STATUS_IS_OK(net_update_dns(ctx
, ads
)) ) {
1370 d_fprintf( stderr
, "DNS update failed!\n" );
1371 ads_destroy( &ads
);
1376 d_fprintf( stderr
, "Successfully registered hostname with DNS\n" );
1383 d_fprintf(stderr
, "DNS update support not enabled at compile time!\n");
1388 #if defined(WITH_DNS_UPDATES)
1389 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1392 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1394 #if defined(WITH_DNS_UPDATES)
1398 talloc_enable_leak_report();
1401 if (argc
!= 2 || c
->display_usage
) {
1403 "net ads dns gethostbyname <server> <name>\n"
1404 " Look up hostname from the AD\n"
1405 " server\tName server to use\n"
1406 " name\tName to look up\n");
1410 err
= do_gethostbyname(argv
[0], argv
[1]);
1412 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err
));
1417 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1419 struct functable func
[] = {
1422 net_ads_dns_register
,
1424 "Add host dns entry to AD",
1425 "net ads dns register\n"
1426 " Add host dns entry to AD"
1430 net_ads_dns_gethostbyname
,
1433 "net ads dns gethostbyname\n"
1436 {NULL
, NULL
, 0, NULL
, NULL
}
1439 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1442 /*******************************************************************
1443 ********************************************************************/
1445 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1448 "\nnet ads printer search <printer>"
1449 "\n\tsearch for a printer in the directory\n"
1450 "\nnet ads printer info <printer> <server>"
1451 "\n\tlookup info in directory for printer on server"
1452 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1453 "\nnet ads printer publish <printername>"
1454 "\n\tpublish printer in directory"
1455 "\n\t(note: printer name is required)\n"
1456 "\nnet ads printer remove <printername>"
1457 "\n\tremove printer from directory"
1458 "\n\t(note: printer name is required)\n");
1462 /*******************************************************************
1463 ********************************************************************/
1465 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1469 LDAPMessage
*res
= NULL
;
1471 if (c
->display_usage
) {
1473 "net ads printer search\n"
1474 " List printers in the AD\n");
1478 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1482 rc
= ads_find_printers(ads
, &res
);
1484 if (!ADS_ERR_OK(rc
)) {
1485 d_fprintf(stderr
, "ads_find_printer: %s\n", ads_errstr(rc
));
1486 ads_msgfree(ads
, res
);
1491 if (ads_count_replies(ads
, res
) == 0) {
1492 d_fprintf(stderr
, "No results found\n");
1493 ads_msgfree(ads
, res
);
1499 ads_msgfree(ads
, res
);
1504 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1508 const char *servername
, *printername
;
1509 LDAPMessage
*res
= NULL
;
1511 if (c
->display_usage
) {
1513 "net ads printer info [printername [servername]]\n"
1514 " Display printer info from AD\n"
1515 " printername\tPrinter name or wildcard\n"
1516 " servername\tName of the print server\n");
1520 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1525 printername
= argv
[0];
1531 servername
= argv
[1];
1533 servername
= global_myname();
1536 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1538 if (!ADS_ERR_OK(rc
)) {
1539 d_fprintf(stderr
, "Server '%s' not found: %s\n",
1540 servername
, ads_errstr(rc
));
1541 ads_msgfree(ads
, res
);
1546 if (ads_count_replies(ads
, res
) == 0) {
1547 d_fprintf(stderr
, "Printer '%s' not found\n", printername
);
1548 ads_msgfree(ads
, res
);
1554 ads_msgfree(ads
, res
);
1560 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1564 const char *servername
, *printername
;
1565 struct cli_state
*cli
;
1566 struct rpc_pipe_client
*pipe_hnd
;
1567 struct sockaddr_storage server_ss
;
1569 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1570 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1571 char *prt_dn
, *srv_dn
, **srv_cn
;
1572 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1573 LDAPMessage
*res
= NULL
;
1575 if (argc
< 1 || c
->display_usage
) {
1577 "net ads printer publish <printername> [servername]\n"
1578 " Publish printer in AD\n"
1579 " printername\tName of the printer\n"
1580 " servername\tName of the print server\n");
1581 talloc_destroy(mem_ctx
);
1585 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1586 talloc_destroy(mem_ctx
);
1590 printername
= argv
[0];
1593 servername
= argv
[1];
1595 servername
= global_myname();
1598 /* Get printer data from SPOOLSS */
1600 resolve_name(servername
, &server_ss
, 0x20);
1602 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1605 c
->opt_user_name
, c
->opt_workgroup
,
1606 c
->opt_password
? c
->opt_password
: "",
1607 CLI_FULL_CONNECTION_USE_KERBEROS
,
1610 if (NT_STATUS_IS_ERR(nt_status
)) {
1611 d_fprintf(stderr
, "Unable to open a connnection to %s to obtain data "
1612 "for %s\n", servername
, printername
);
1614 talloc_destroy(mem_ctx
);
1618 /* Publish on AD server */
1620 ads_find_machine_acct(ads
, &res
, servername
);
1622 if (ads_count_replies(ads
, res
) == 0) {
1623 d_fprintf(stderr
, "Could not find machine account for server %s\n",
1626 talloc_destroy(mem_ctx
);
1630 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1631 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1633 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1634 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1635 if (!srv_cn_escaped
|| !printername_escaped
) {
1636 SAFE_FREE(srv_cn_escaped
);
1637 SAFE_FREE(printername_escaped
);
1638 d_fprintf(stderr
, "Internal error, out of memory!");
1640 talloc_destroy(mem_ctx
);
1644 if (asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
) == -1) {
1645 SAFE_FREE(srv_cn_escaped
);
1646 SAFE_FREE(printername_escaped
);
1647 d_fprintf(stderr
, "Internal error, out of memory!");
1649 talloc_destroy(mem_ctx
);
1653 SAFE_FREE(srv_cn_escaped
);
1654 SAFE_FREE(printername_escaped
);
1656 nt_status
= cli_rpc_pipe_open_noauth(cli
, &syntax_spoolss
, &pipe_hnd
);
1657 if (!NT_STATUS_IS_OK(nt_status
)) {
1658 d_fprintf(stderr
, "Unable to open a connnection to the spoolss pipe on %s\n",
1662 talloc_destroy(mem_ctx
);
1666 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1670 talloc_destroy(mem_ctx
);
1674 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1675 if (!ADS_ERR_OK(rc
)) {
1676 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1679 talloc_destroy(mem_ctx
);
1683 d_printf("published printer\n");
1686 talloc_destroy(mem_ctx
);
1691 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1695 const char *servername
;
1697 LDAPMessage
*res
= NULL
;
1699 if (argc
< 1 || c
->display_usage
) {
1701 "net ads printer remove <printername> [servername]\n"
1702 " Remove a printer from the AD\n"
1703 " printername\tName of the printer\n"
1704 " servername\tName of the print server\n");
1708 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1713 servername
= argv
[1];
1715 servername
= global_myname();
1718 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1720 if (!ADS_ERR_OK(rc
)) {
1721 d_fprintf(stderr
, "ads_find_printer_on_server: %s\n", ads_errstr(rc
));
1722 ads_msgfree(ads
, res
);
1727 if (ads_count_replies(ads
, res
) == 0) {
1728 d_fprintf(stderr
, "Printer '%s' not found\n", argv
[1]);
1729 ads_msgfree(ads
, res
);
1734 prt_dn
= ads_get_dn(ads
, res
);
1735 ads_msgfree(ads
, res
);
1736 rc
= ads_del_dn(ads
, prt_dn
);
1737 ads_memfree(ads
, prt_dn
);
1739 if (!ADS_ERR_OK(rc
)) {
1740 d_fprintf(stderr
, "ads_del_dn: %s\n", ads_errstr(rc
));
1749 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
1751 struct functable func
[] = {
1754 net_ads_printer_search
,
1756 "Search for a printer",
1757 "net ads printer search\n"
1758 " Search for a printer"
1762 net_ads_printer_info
,
1764 "Display printer information",
1765 "net ads printer info\n"
1766 " Display printer information"
1770 net_ads_printer_publish
,
1772 "Publish a printer",
1773 "net ads printer publish\n"
1774 " Publish a printer"
1778 net_ads_printer_remove
,
1781 "net ads printer remove\n"
1784 {NULL
, NULL
, 0, NULL
, NULL
}
1787 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
1791 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
1794 const char *auth_principal
= c
->opt_user_name
;
1795 const char *auth_password
= c
->opt_password
;
1797 char *new_password
= NULL
;
1802 if (c
->display_usage
) {
1804 "net ads password <username>\n"
1805 " Change password for user\n"
1806 " username\tName of user to change password for\n");
1810 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
1811 d_fprintf(stderr
, "You must supply an administrator username/password\n");
1816 d_fprintf(stderr
, "ERROR: You must say which username to change password for\n");
1821 if (!strchr_m(user
, '@')) {
1822 if (asprintf(&chr
, "%s@%s", argv
[0], lp_realm()) == -1) {
1828 use_in_memory_ccache();
1829 chr
= strchr_m(auth_principal
, '@');
1836 /* use the realm so we can eventually change passwords for users
1837 in realms other than default */
1838 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
1842 /* we don't actually need a full connect, but it's the easy way to
1843 fill in the KDC's addresss */
1846 if (!ads
->config
.realm
) {
1847 d_fprintf(stderr
, "Didn't find the kerberos server!\n");
1852 new_password
= (char *)argv
[1];
1854 if (asprintf(&prompt
, "Enter new password for %s:", user
) == -1) {
1857 new_password
= getpass(prompt
);
1861 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
1862 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
1863 if (!ADS_ERR_OK(ret
)) {
1864 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1869 d_printf("Password change for %s completed.\n", user
);
1875 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
1878 char *host_principal
;
1882 if (c
->display_usage
) {
1884 "net ads changetrustpw\n"
1885 " Change the machine account's trust password\n");
1889 if (!secrets_init()) {
1890 DEBUG(1,("Failed to initialise secrets database\n"));
1894 net_use_krb_machine_account(c
);
1896 use_in_memory_ccache();
1898 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1902 fstrcpy(my_name
, global_myname());
1903 strlower_m(my_name
);
1904 if (asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
) == -1) {
1908 d_printf("Changing password for principal: %s\n", host_principal
);
1910 ret
= ads_change_trust_account_password(ads
, host_principal
);
1912 if (!ADS_ERR_OK(ret
)) {
1913 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1915 SAFE_FREE(host_principal
);
1919 d_printf("Password change for principal %s succeeded.\n", host_principal
);
1921 if (lp_use_kerberos_keytab()) {
1922 d_printf("Attempting to update system keytab with new password.\n");
1923 if (ads_keytab_create_default(ads
)) {
1924 d_printf("Failed to update system keytab.\n");
1929 SAFE_FREE(host_principal
);
1935 help for net ads search
1937 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
1940 "\nnet ads search <expression> <attributes...>\n"
1941 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1942 "The expression is a standard LDAP search expression, and the\n"
1943 "attributes are a list of LDAP fields to show in the results.\n\n"
1944 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1946 net_common_flags_usage(c
, argc
, argv
);
1952 general ADS search function. Useful in diagnosing problems in ADS
1954 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
1958 const char *ldap_exp
;
1960 LDAPMessage
*res
= NULL
;
1962 if (argc
< 1 || c
->display_usage
) {
1963 return net_ads_search_usage(c
, argc
, argv
);
1966 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1973 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
1975 ldap_exp
, attrs
, &res
);
1976 if (!ADS_ERR_OK(rc
)) {
1977 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
1982 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
1984 /* dump the results */
1987 ads_msgfree(ads
, res
);
1995 help for net ads search
1997 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
2000 "\nnet ads dn <dn> <attributes...>\n"
2001 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2002 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2003 "to show in the results\n\n"
2004 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2005 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2007 net_common_flags_usage(c
, argc
, argv
);
2013 general ADS search function. Useful in diagnosing problems in ADS
2015 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
2021 LDAPMessage
*res
= NULL
;
2023 if (argc
< 1 || c
->display_usage
) {
2024 return net_ads_dn_usage(c
, argc
, argv
);
2027 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2034 rc
= ads_do_search_all(ads
, dn
,
2036 "(objectclass=*)", attrs
, &res
);
2037 if (!ADS_ERR_OK(rc
)) {
2038 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
2043 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2045 /* dump the results */
2048 ads_msgfree(ads
, res
);
2055 help for net ads sid search
2057 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2060 "\nnet ads sid <sid> <attributes...>\n"
2061 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2062 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2063 "to show in the results\n\n"
2064 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2066 net_common_flags_usage(c
, argc
, argv
);
2072 general ADS search function. Useful in diagnosing problems in ADS
2074 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2078 const char *sid_string
;
2080 LDAPMessage
*res
= NULL
;
2083 if (argc
< 1 || c
->display_usage
) {
2084 return net_ads_sid_usage(c
, argc
, argv
);
2087 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2091 sid_string
= argv
[0];
2094 if (!string_to_sid(&sid
, sid_string
)) {
2095 d_fprintf(stderr
, "could not convert sid\n");
2100 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2101 if (!ADS_ERR_OK(rc
)) {
2102 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
2107 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2109 /* dump the results */
2112 ads_msgfree(ads
, res
);
2118 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2123 if (c
->display_usage
) {
2125 "net ads keytab flush\n"
2126 " Delete the whole keytab\n");
2130 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2133 ret
= ads_keytab_flush(ads
);
2138 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2144 if (c
->display_usage
) {
2146 "net ads keytab add <principal> [principal ...]\n"
2147 " Add principals to local keytab\n"
2148 " principal\tKerberos principal to add to "
2153 d_printf("Processing principals to add...\n");
2154 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2157 for (i
= 0; i
< argc
; i
++) {
2158 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2164 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2169 if (c
->display_usage
) {
2171 "net ads keytab create\n"
2172 " Create new default keytab\n");
2176 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2179 ret
= ads_keytab_create_default(ads
);
2184 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2186 const char *keytab
= NULL
;
2188 if (c
->display_usage
) {
2190 "net ads keytab list [keytab]\n"
2191 " List a local keytab\n"
2192 " keytab\tKeytab to list\n");
2200 return ads_keytab_list(keytab
);
2204 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2206 struct functable func
[] = {
2211 "Add a service principal",
2212 "net ads keytab add\n"
2213 " Add a service principal"
2217 net_ads_keytab_create
,
2219 "Create a fresh keytab",
2220 "net ads keytab create\n"
2221 " Create a fresh keytab"
2225 net_ads_keytab_flush
,
2227 "Remove all keytab entries",
2228 "net ads keytab flush\n"
2229 " Remove all keytab entries"
2233 net_ads_keytab_list
,
2236 "net ads keytab list\n"
2239 {NULL
, NULL
, 0, NULL
, NULL
}
2242 if (!lp_use_kerberos_keytab()) {
2243 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2244 use keytab functions.\n");
2247 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2250 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2254 if (c
->display_usage
) {
2256 "net ads kerberos renew\n"
2257 " Renew TGT from existing credential cache\n");
2261 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2263 d_printf("failed to renew kerberos ticket: %s\n",
2264 error_message(ret
));
2269 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2271 struct PAC_DATA
*pac
= NULL
;
2272 struct PAC_LOGON_INFO
*info
= NULL
;
2273 TALLOC_CTX
*mem_ctx
= NULL
;
2277 if (c
->display_usage
) {
2279 "net ads kerberos pac\n"
2280 " Dump the Kerberos PAC\n");
2284 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2289 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2291 status
= kerberos_return_pac(mem_ctx
,
2300 2592000, /* one month */
2302 if (!NT_STATUS_IS_OK(status
)) {
2303 d_printf("failed to query kerberos PAC: %s\n",
2308 info
= get_logon_info_from_pac(pac
);
2311 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2312 d_printf("The Pac: %s\n", s
);
2317 TALLOC_FREE(mem_ctx
);
2321 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2323 TALLOC_CTX
*mem_ctx
= NULL
;
2327 if (c
->display_usage
) {
2329 "net ads kerberos kinit\n"
2330 " Get Ticket Granting Ticket (TGT) for the user\n");
2334 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2339 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2341 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2349 2592000, /* one month */
2352 d_printf("failed to kinit password: %s\n",
2359 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2361 struct functable func
[] = {
2364 net_ads_kerberos_kinit
,
2366 "Retrieve Ticket Granting Ticket (TGT)",
2367 "net ads kerberos kinit\n"
2368 " Receive Ticket Granting Ticket (TGT)"
2372 net_ads_kerberos_renew
,
2374 "Renew Ticket Granting Ticket from credential cache"
2375 "net ads kerberos renew\n"
2376 " Renew Ticket Granting Ticket from credential cache"
2380 net_ads_kerberos_pac
,
2382 "Dump Kerberos PAC",
2383 "net ads kerberos pac\n"
2384 " Dump Kerberos PAC"
2386 {NULL
, NULL
, 0, NULL
, NULL
}
2389 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2392 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2394 struct functable func
[] = {
2399 "Display details on remote ADS server",
2401 " Display details on remote ADS server"
2407 "Join the local machine to ADS realm",
2409 " Join the local machine to ADS realm"
2415 "Validate machine account",
2416 "net ads testjoin\n"
2417 " Validate machine account"
2423 "Remove the local machine from ADS",
2425 " Remove the local machine from ADS"
2431 "Display machine account details",
2433 " Display machine account details"
2439 "List/modify users",
2441 " List/modify users"
2447 "List/modify groups",
2449 " List/modify groups"
2455 "Issue dynamic DNS update",
2457 " Issue dynamic DNS update"
2463 "Change user passwords",
2464 "net ads password\n"
2465 " Change user passwords"
2469 net_ads_changetrustpw
,
2471 "Change trust account password",
2472 "net ads changetrustpw\n"
2473 " Change trust account password"
2479 "List/modify printer entries",
2481 " List/modify printer entries"
2487 "Issue LDAP search using filter",
2489 " Issue LDAP search using filter"
2495 "Issue LDAP search by DN",
2497 " Issue LDAP search by DN"
2503 "Issue LDAP search by SID",
2505 " Issue LDAP search by SID"
2511 "Display workgroup name",
2512 "net ads workgroup\n"
2513 " Display the workgroup name"
2519 "Perfom CLDAP query on DC",
2521 " Find the ADS DC using CLDAP lookups"
2527 "Manage local keytab file",
2529 " Manage local keytab file"
2535 "Manage group policy objects",
2537 " Manage group policy objects"
2543 "Manage kerberos keytab",
2544 "net ads kerberos\n"
2545 " Manage kerberos keytab"
2547 {NULL
, NULL
, 0, NULL
, NULL
}
2550 return net_run_function(c
, argc
, argv
, "net ads", func
);
2555 static int net_ads_noads(void)
2557 d_fprintf(stderr
, "ADS support not compiled in\n");
2561 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2563 return net_ads_noads();
2566 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2568 return net_ads_noads();
2571 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2573 return net_ads_noads();
2576 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2578 return net_ads_noads();
2581 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2583 return net_ads_noads();
2586 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2588 return net_ads_noads();
2591 /* this one shouldn't display a message */
2592 int net_ads_check(struct net_context
*c
)
2597 int net_ads_check_our_domain(struct net_context
*c
)
2602 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2604 return net_ads_noads();
2607 #endif /* WITH_ADS */