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
->config
.tried_closest_dc
) {
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 asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
);
480 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
481 ads
->auth
.time_offset
);
483 if (ADS_ERR_OK(status
)) {
484 d_printf("User %s added\n", argv
[0]);
489 /* password didn't set, delete account */
490 d_fprintf(stderr
, "Could not add user %s. Error setting password %s\n",
491 argv
[0], ads_errstr(status
));
492 ads_msgfree(ads
, res
);
493 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
494 if (ADS_ERR_OK(status
)) {
495 userdn
= ads_get_dn(ads
, res
);
496 ads_del_dn(ads
, userdn
);
497 ads_memfree(ads
, userdn
);
502 ads_msgfree(ads
, res
);
508 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
513 const char *attrs
[] = {"memberOf", NULL
};
514 char *searchstring
=NULL
;
518 if (argc
< 1 || c
->display_usage
) {
519 return net_ads_user_usage(c
, argc
, argv
);
522 escaped_user
= escape_ldap_string_alloc(argv
[0]);
525 d_fprintf(stderr
, "ads_user_info: failed to escape user %s\n", argv
[0]);
529 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
530 SAFE_FREE(escaped_user
);
534 asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
);
535 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
536 safe_free(searchstring
);
538 if (!ADS_ERR_OK(rc
)) {
539 d_fprintf(stderr
, "ads_search: %s\n", ads_errstr(rc
));
541 SAFE_FREE(escaped_user
);
545 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
546 (LDAPMessage
*)res
, "memberOf");
551 for (i
=0;grouplist
[i
];i
++) {
552 groupname
= ldap_explode_dn(grouplist
[i
], 1);
553 d_printf("%s\n", groupname
[0]);
554 ldap_value_free(groupname
);
556 ldap_value_free(grouplist
);
559 ads_msgfree(ads
, res
);
561 SAFE_FREE(escaped_user
);
565 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
569 LDAPMessage
*res
= NULL
;
573 return net_ads_user_usage(c
, argc
, argv
);
576 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
580 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
581 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
582 d_printf("User %s does not exist.\n", argv
[0]);
583 ads_msgfree(ads
, res
);
587 userdn
= ads_get_dn(ads
, res
);
588 ads_msgfree(ads
, res
);
589 rc
= ads_del_dn(ads
, userdn
);
590 ads_memfree(ads
, userdn
);
591 if (ADS_ERR_OK(rc
)) {
592 d_printf("User %s deleted\n", argv
[0]);
596 d_fprintf(stderr
, "Error deleting user %s: %s\n", argv
[0],
602 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
604 struct functable func
[] = {
617 "Display information about an AD user",
618 "net ads user info\n"
619 " Display information about an AD user"
626 "net ads user delete\n"
629 {NULL
, NULL
, 0, NULL
, NULL
}
633 const char *shortattrs
[] = {"sAMAccountName", NULL
};
634 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
635 char *disp_fields
[2] = {NULL
, NULL
};
638 if (c
->display_usage
) {
639 d_printf("Usage:\n");
640 d_printf("net ads user\n"
642 net_display_usage_from_functable(func
);
646 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
650 if (c
->opt_long_list_entries
)
651 d_printf("\nUser name Comment"
652 "\n-----------------------------\n");
654 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
656 "(objectCategory=user)",
657 c
->opt_long_list_entries
? longattrs
:
658 shortattrs
, usergrp_display
,
661 return ADS_ERR_OK(rc
) ? 0 : -1;
664 return net_run_function(c
, argc
, argv
, "net ads user", func
);
667 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
669 return net_group_usage(c
, argc
, argv
);
672 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
676 LDAPMessage
*res
=NULL
;
680 if (argc
< 1 || c
->display_usage
) {
681 return net_ads_group_usage(c
, argc
, argv
);
684 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
688 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
690 if (!ADS_ERR_OK(status
)) {
691 d_fprintf(stderr
, "ads_group_add: %s\n", ads_errstr(status
));
695 if (ads_count_replies(ads
, res
)) {
696 d_fprintf(stderr
, "ads_group_add: Group %s already exists\n", argv
[0]);
700 if (c
->opt_container
) {
701 ou_str
= SMB_STRDUP(c
->opt_container
);
703 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
706 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
708 if (ADS_ERR_OK(status
)) {
709 d_printf("Group %s added\n", argv
[0]);
712 d_fprintf(stderr
, "Could not add group %s: %s\n", argv
[0],
718 ads_msgfree(ads
, res
);
724 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
728 LDAPMessage
*res
= NULL
;
731 if (argc
< 1 || c
->display_usage
) {
732 return net_ads_group_usage(c
, argc
, argv
);
735 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
739 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
740 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
741 d_printf("Group %s does not exist.\n", argv
[0]);
742 ads_msgfree(ads
, res
);
746 groupdn
= ads_get_dn(ads
, res
);
747 ads_msgfree(ads
, res
);
748 rc
= ads_del_dn(ads
, groupdn
);
749 ads_memfree(ads
, groupdn
);
750 if (ADS_ERR_OK(rc
)) {
751 d_printf("Group %s deleted\n", argv
[0]);
755 d_fprintf(stderr
, "Error deleting group %s: %s\n", argv
[0],
761 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
763 struct functable func
[] = {
769 "net ads group add\n"
776 "Delete an AD group",
777 "net ads group delete\n"
778 " Delete an AD group"
780 {NULL
, NULL
, 0, NULL
, NULL
}
784 const char *shortattrs
[] = {"sAMAccountName", NULL
};
785 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
786 char *disp_fields
[2] = {NULL
, NULL
};
789 if (c
->display_usage
) {
790 d_printf("Usage:\n");
791 d_printf("net ads group\n"
792 " List AD groups\n");
793 net_display_usage_from_functable(func
);
797 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
801 if (c
->opt_long_list_entries
)
802 d_printf("\nGroup name Comment"
803 "\n-----------------------------\n");
804 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
806 "(objectCategory=group)",
807 c
->opt_long_list_entries
? longattrs
:
808 shortattrs
, usergrp_display
,
812 return ADS_ERR_OK(rc
) ? 0 : -1;
814 return net_run_function(c
, argc
, argv
, "net ads group", func
);
817 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
823 if (c
->display_usage
) {
826 " Display machine account details\n");
830 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
834 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
835 if (!ADS_ERR_OK(rc
)) {
836 d_fprintf(stderr
, "ads_find_machine_acct: %s\n", ads_errstr(rc
));
841 if (ads_count_replies(ads
, res
) == 0) {
842 d_fprintf(stderr
, "No machine account for '%s' found\n", global_myname());
852 /*******************************************************************
853 Leave an AD domain. Windows XP disables the machine account.
854 We'll try the same. The old code would do an LDAP delete.
855 That only worked using the machine creds because added the machine
856 with full control to the computer object's ACL.
857 *******************************************************************/
859 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
862 struct libnet_UnjoinCtx
*r
= NULL
;
865 if (c
->display_usage
) {
868 " Leave an AD domain\n");
873 d_fprintf(stderr
, "No realm set, are we joined ?\n");
877 if (!(ctx
= talloc_init("net_ads_leave"))) {
878 d_fprintf(stderr
, "Could not initialise talloc context.\n");
882 if (!c
->opt_kerberos
) {
883 use_in_memory_ccache();
886 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
887 if (!W_ERROR_IS_OK(werr
)) {
888 d_fprintf(stderr
, "Could not initialise unjoin context.\n");
893 r
->in
.use_kerberos
= c
->opt_kerberos
;
894 r
->in
.dc_name
= c
->opt_host
;
895 r
->in
.domain_name
= lp_realm();
896 r
->in
.admin_account
= c
->opt_user_name
;
897 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
898 r
->in
.modify_config
= lp_config_backend_is_registry();
899 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
900 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
902 werr
= libnet_Unjoin(ctx
, r
);
903 if (!W_ERROR_IS_OK(werr
)) {
904 d_printf("Failed to leave domain: %s\n",
905 r
->out
.error_string
? r
->out
.error_string
:
906 get_friendly_werror_msg(werr
));
910 if (W_ERROR_IS_OK(werr
)) {
911 d_printf("Deleted account for '%s' in realm '%s'\n",
912 r
->in
.machine_name
, r
->out
.dns_domain_name
);
916 /* We couldn't delete it - see if the disable succeeded. */
917 if (r
->out
.disabled_machine_account
) {
918 d_printf("Disabled account for '%s' in realm '%s'\n",
919 r
->in
.machine_name
, r
->out
.dns_domain_name
);
924 d_fprintf(stderr
, "Failed to disable machine account for '%s' in realm '%s'\n",
925 r
->in
.machine_name
, r
->out
.dns_domain_name
);
931 if (W_ERROR_IS_OK(werr
)) {
938 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
940 ADS_STRUCT
*ads
= NULL
;
943 if (!secrets_init()) {
944 DEBUG(1,("Failed to initialise secrets database\n"));
945 return NT_STATUS_ACCESS_DENIED
;
948 net_use_krb_machine_account(c
);
950 status
= ads_startup(c
, true, &ads
);
951 if (!ADS_ERR_OK(status
)) {
952 return ads_ntstatus(status
);
960 check that an existing join is OK
962 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
965 use_in_memory_ccache();
967 if (c
->display_usage
) {
970 " Test if the existing join is ok\n");
974 /* Display success or failure */
975 status
= net_ads_join_ok(c
);
976 if (!NT_STATUS_IS_OK(status
)) {
977 fprintf(stderr
,"Join to domain is not valid: %s\n",
978 get_friendly_nt_error_msg(status
));
982 printf("Join is OK\n");
986 /*******************************************************************
987 Simple configu checks before beginning the join
988 ********************************************************************/
990 static WERROR
check_ads_config( void )
992 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
993 d_printf("Host is not configured as a member server.\n");
994 return WERR_INVALID_DOMAIN_ROLE
;
997 if (strlen(global_myname()) > 15) {
998 d_printf("Our netbios name can be at most 15 chars long, "
999 "\"%s\" is %u chars long\n", global_myname(),
1000 (unsigned int)strlen(global_myname()));
1001 return WERR_INVALID_COMPUTER_NAME
;
1004 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1005 d_fprintf(stderr
, "realm must be set in in %s for ADS "
1006 "join to succeed.\n", get_dyn_CONFIGFILE());
1007 return WERR_INVALID_PARAM
;
1013 /*******************************************************************
1014 Send a DNS update request
1015 *******************************************************************/
1017 #if defined(WITH_DNS_UPDATES)
1019 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
1020 const char *pszDomainName
, const char *pszHostName
,
1021 const struct sockaddr_storage
*sslist
,
1024 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1025 const char *machine_name
,
1026 const struct sockaddr_storage
*addrs
,
1029 struct dns_rr_ns
*nameservers
= NULL
;
1031 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1034 const char *dnsdomain
= NULL
;
1035 char *root_domain
= NULL
;
1037 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1038 d_printf("No DNS domain configured for %s. "
1039 "Unable to perform DNS Update.\n", machine_name
);
1040 status
= NT_STATUS_INVALID_PARAMETER
;
1045 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
1046 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1047 /* Child domains often do not have NS records. Look
1048 for the NS record for the forest root domain
1049 (rootDomainNamingContext in therootDSE) */
1051 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1052 LDAPMessage
*msg
= NULL
;
1054 ADS_STATUS ads_status
;
1056 if ( !ads
->ldap
.ld
) {
1057 ads_status
= ads_connect( ads
);
1058 if ( !ADS_ERR_OK(ads_status
) ) {
1059 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1064 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1065 "(objectclass=*)", rootname_attrs
, &msg
);
1066 if (!ADS_ERR_OK(ads_status
)) {
1070 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1072 ads_msgfree( ads
, msg
);
1076 root_domain
= ads_build_domain( root_dn
);
1079 ads_msgfree( ads
, msg
);
1081 /* try again for NS servers */
1083 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1085 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1086 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1087 "realm\n", ads
->config
.realm
));
1091 dnsdomain
= root_domain
;
1095 /* Now perform the dns update - we'll try non-secure and if we fail,
1096 we'll follow it up with a secure update */
1098 fstrcpy( dns_server
, nameservers
[0].hostname
);
1100 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1101 if (!ERR_DNS_IS_OK(dns_err
)) {
1102 status
= NT_STATUS_UNSUCCESSFUL
;
1107 SAFE_FREE( root_domain
);
1112 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
)
1115 struct sockaddr_storage
*iplist
= NULL
;
1116 fstring machine_name
;
1119 name_to_fqdn( machine_name
, global_myname() );
1120 strlower_m( machine_name
);
1122 /* Get our ip address (not the 127.0.0.x address but a real ip
1125 num_addrs
= get_my_ip_address( &iplist
);
1126 if ( num_addrs
<= 0 ) {
1127 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1129 return NT_STATUS_INVALID_PARAMETER
;
1132 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1134 SAFE_FREE( iplist
);
1140 /*******************************************************************
1141 ********************************************************************/
1143 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1145 d_printf("net ads join [options]\n");
1146 d_printf("Valid options:\n");
1147 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1148 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1149 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1150 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1151 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1152 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1153 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1154 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1155 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1156 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1157 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1158 d_printf(" the two other attributes.\n");
1163 /*******************************************************************
1164 ********************************************************************/
1166 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1168 TALLOC_CTX
*ctx
= NULL
;
1169 struct libnet_JoinCtx
*r
= NULL
;
1170 const char *domain
= lp_realm();
1171 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1172 bool createupn
= false;
1173 const char *machineupn
= NULL
;
1174 const char *create_in_ou
= NULL
;
1176 const char *os_name
= NULL
;
1177 const char *os_version
= NULL
;
1178 bool modify_config
= lp_config_backend_is_registry();
1180 if (c
->display_usage
)
1181 return net_ads_join_usage(c
, argc
, argv
);
1183 if (!modify_config
) {
1185 werr
= check_ads_config();
1186 if (!W_ERROR_IS_OK(werr
)) {
1187 d_fprintf(stderr
, "Invalid configuration. Exiting....\n");
1192 if (!(ctx
= talloc_init("net_ads_join"))) {
1193 d_fprintf(stderr
, "Could not initialise talloc context.\n");
1198 if (!c
->opt_kerberos
) {
1199 use_in_memory_ccache();
1202 werr
= libnet_init_JoinCtx(ctx
, &r
);
1203 if (!W_ERROR_IS_OK(werr
)) {
1207 /* process additional command line args */
1209 for ( i
=0; i
<argc
; i
++ ) {
1210 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1212 machineupn
= get_string_param(argv
[i
]);
1214 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1215 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1216 d_fprintf(stderr
, "Please supply a valid OU path.\n");
1217 werr
= WERR_INVALID_PARAM
;
1221 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1222 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1223 d_fprintf(stderr
, "Please supply a operating system name.\n");
1224 werr
= WERR_INVALID_PARAM
;
1228 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1229 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1230 d_fprintf(stderr
, "Please supply a valid operating system version.\n");
1231 werr
= WERR_INVALID_PARAM
;
1241 d_fprintf(stderr
, "Please supply a valid domain name\n");
1242 werr
= WERR_INVALID_PARAM
;
1246 /* Do the domain join here */
1248 r
->in
.domain_name
= domain
;
1249 r
->in
.create_upn
= createupn
;
1250 r
->in
.upn
= machineupn
;
1251 r
->in
.account_ou
= create_in_ou
;
1252 r
->in
.os_name
= os_name
;
1253 r
->in
.os_version
= os_version
;
1254 r
->in
.dc_name
= c
->opt_host
;
1255 r
->in
.admin_account
= c
->opt_user_name
;
1256 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1258 r
->in
.use_kerberos
= c
->opt_kerberos
;
1259 r
->in
.modify_config
= modify_config
;
1260 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1261 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1262 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1264 werr
= libnet_Join(ctx
, r
);
1265 if (!W_ERROR_IS_OK(werr
)) {
1269 /* Check the short name of the domain */
1271 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1272 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1273 d_printf("domain name obtained from the server.\n");
1274 d_printf("Using the name [%s] from the server.\n", r
->out
.netbios_domain_name
);
1275 d_printf("You should set \"workgroup = %s\" in %s.\n",
1276 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1279 d_printf("Using short domain name -- %s\n", r
->out
.netbios_domain_name
);
1281 if (r
->out
.dns_domain_name
) {
1282 d_printf("Joined '%s' to realm '%s'\n", r
->in
.machine_name
,
1283 r
->out
.dns_domain_name
);
1285 d_printf("Joined '%s' to domain '%s'\n", r
->in
.machine_name
,
1286 r
->out
.netbios_domain_name
);
1289 #if defined(WITH_DNS_UPDATES)
1290 if (r
->out
.domain_is_ad
) {
1291 /* We enter this block with user creds */
1292 ADS_STRUCT
*ads_dns
= NULL
;
1294 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1295 /* kinit with the machine password */
1297 use_in_memory_ccache();
1298 asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname() );
1299 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1300 r
->out
.netbios_domain_name
, NULL
, NULL
);
1301 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1302 strupper_m(ads_dns
->auth
.realm
);
1303 ads_kinit_password( ads_dns
);
1306 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns( ctx
, ads_dns
)) ) {
1307 d_fprintf( stderr
, "DNS update failed!\n" );
1310 /* exit from this block using machine creds */
1311 ads_destroy(&ads_dns
);
1320 /* issue an overall failure message at the end. */
1321 d_printf("Failed to join domain: %s\n",
1322 r
&& r
->out
.error_string
? r
->out
.error_string
:
1323 get_friendly_werror_msg(werr
));
1329 /*******************************************************************
1330 ********************************************************************/
1332 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1334 #if defined(WITH_DNS_UPDATES)
1340 talloc_enable_leak_report();
1343 if (argc
> 0 || c
->display_usage
) {
1345 "net ads dns register\n"
1346 " Register hostname with DNS\n");
1350 if (!(ctx
= talloc_init("net_ads_dns"))) {
1351 d_fprintf(stderr
, "Could not initialise talloc context\n");
1355 status
= ads_startup(c
, true, &ads
);
1356 if ( !ADS_ERR_OK(status
) ) {
1357 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1362 if ( !NT_STATUS_IS_OK(net_update_dns(ctx
, ads
)) ) {
1363 d_fprintf( stderr
, "DNS update failed!\n" );
1364 ads_destroy( &ads
);
1369 d_fprintf( stderr
, "Successfully registered hostname with DNS\n" );
1376 d_fprintf(stderr
, "DNS update support not enabled at compile time!\n");
1381 #if defined(WITH_DNS_UPDATES)
1382 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1385 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1387 #if defined(WITH_DNS_UPDATES)
1391 talloc_enable_leak_report();
1394 if (argc
!= 2 || c
->display_usage
) {
1396 "net ads dns gethostbyname <server> <name>\n"
1397 " Look up hostname from the AD\n"
1398 " server\tName server to use\n"
1399 " name\tName to look up\n");
1403 err
= do_gethostbyname(argv
[0], argv
[1]);
1405 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err
));
1410 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1412 struct functable func
[] = {
1415 net_ads_dns_register
,
1417 "Add host dns entry to AD",
1418 "net ads dns register\n"
1419 " Add host dns entry to AD"
1423 net_ads_dns_gethostbyname
,
1426 "net ads dns gethostbyname\n"
1429 {NULL
, NULL
, 0, NULL
, NULL
}
1432 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1435 /*******************************************************************
1436 ********************************************************************/
1438 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1441 "\nnet ads printer search <printer>"
1442 "\n\tsearch for a printer in the directory\n"
1443 "\nnet ads printer info <printer> <server>"
1444 "\n\tlookup info in directory for printer on server"
1445 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1446 "\nnet ads printer publish <printername>"
1447 "\n\tpublish printer in directory"
1448 "\n\t(note: printer name is required)\n"
1449 "\nnet ads printer remove <printername>"
1450 "\n\tremove printer from directory"
1451 "\n\t(note: printer name is required)\n");
1455 /*******************************************************************
1456 ********************************************************************/
1458 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1462 LDAPMessage
*res
= NULL
;
1464 if (c
->display_usage
) {
1466 "net ads printer search\n"
1467 " List printers in the AD\n");
1471 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1475 rc
= ads_find_printers(ads
, &res
);
1477 if (!ADS_ERR_OK(rc
)) {
1478 d_fprintf(stderr
, "ads_find_printer: %s\n", ads_errstr(rc
));
1479 ads_msgfree(ads
, res
);
1484 if (ads_count_replies(ads
, res
) == 0) {
1485 d_fprintf(stderr
, "No results found\n");
1486 ads_msgfree(ads
, res
);
1492 ads_msgfree(ads
, res
);
1497 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1501 const char *servername
, *printername
;
1502 LDAPMessage
*res
= NULL
;
1504 if (c
->display_usage
) {
1506 "net ads printer info [printername [servername]]\n"
1507 " Display printer info from AD\n"
1508 " printername\tPrinter name or wildcard\n"
1509 " servername\tName of the print server\n");
1513 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1518 printername
= argv
[0];
1524 servername
= argv
[1];
1526 servername
= global_myname();
1529 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1531 if (!ADS_ERR_OK(rc
)) {
1532 d_fprintf(stderr
, "Server '%s' not found: %s\n",
1533 servername
, ads_errstr(rc
));
1534 ads_msgfree(ads
, res
);
1539 if (ads_count_replies(ads
, res
) == 0) {
1540 d_fprintf(stderr
, "Printer '%s' not found\n", printername
);
1541 ads_msgfree(ads
, res
);
1547 ads_msgfree(ads
, res
);
1553 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1557 const char *servername
, *printername
;
1558 struct cli_state
*cli
;
1559 struct rpc_pipe_client
*pipe_hnd
;
1560 struct sockaddr_storage server_ss
;
1562 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1563 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1564 char *prt_dn
, *srv_dn
, **srv_cn
;
1565 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1566 LDAPMessage
*res
= NULL
;
1568 if (argc
< 1 || c
->display_usage
) {
1570 "net ads printer publish <printername> [servername]\n"
1571 " Publish printer in AD\n"
1572 " printername\tName of the printer\n"
1573 " servername\tName of the print server\n");
1574 talloc_destroy(mem_ctx
);
1578 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1579 talloc_destroy(mem_ctx
);
1583 printername
= argv
[0];
1586 servername
= argv
[1];
1588 servername
= global_myname();
1591 /* Get printer data from SPOOLSS */
1593 resolve_name(servername
, &server_ss
, 0x20);
1595 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1598 c
->opt_user_name
, c
->opt_workgroup
,
1599 c
->opt_password
? c
->opt_password
: "",
1600 CLI_FULL_CONNECTION_USE_KERBEROS
,
1603 if (NT_STATUS_IS_ERR(nt_status
)) {
1604 d_fprintf(stderr
, "Unable to open a connnection to %s to obtain data "
1605 "for %s\n", servername
, printername
);
1607 talloc_destroy(mem_ctx
);
1611 /* Publish on AD server */
1613 ads_find_machine_acct(ads
, &res
, servername
);
1615 if (ads_count_replies(ads
, res
) == 0) {
1616 d_fprintf(stderr
, "Could not find machine account for server %s\n",
1619 talloc_destroy(mem_ctx
);
1623 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1624 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1626 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1627 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1628 if (!srv_cn_escaped
|| !printername_escaped
) {
1629 SAFE_FREE(srv_cn_escaped
);
1630 SAFE_FREE(printername_escaped
);
1631 d_fprintf(stderr
, "Internal error, out of memory!");
1633 talloc_destroy(mem_ctx
);
1637 asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
);
1639 SAFE_FREE(srv_cn_escaped
);
1640 SAFE_FREE(printername_escaped
);
1642 nt_status
= cli_rpc_pipe_open_noauth(cli
, &syntax_spoolss
, &pipe_hnd
);
1643 if (!NT_STATUS_IS_OK(nt_status
)) {
1644 d_fprintf(stderr
, "Unable to open a connnection to the spoolss pipe on %s\n",
1648 talloc_destroy(mem_ctx
);
1652 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1656 talloc_destroy(mem_ctx
);
1660 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1661 if (!ADS_ERR_OK(rc
)) {
1662 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1665 talloc_destroy(mem_ctx
);
1669 d_printf("published printer\n");
1672 talloc_destroy(mem_ctx
);
1677 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1681 const char *servername
;
1683 LDAPMessage
*res
= NULL
;
1685 if (argc
< 1 || c
->display_usage
) {
1687 "net ads printer remove <printername> [servername]\n"
1688 " Remove a printer from the AD\n"
1689 " printername\tName of the printer\n"
1690 " servername\tName of the print server\n");
1694 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1699 servername
= argv
[1];
1701 servername
= global_myname();
1704 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1706 if (!ADS_ERR_OK(rc
)) {
1707 d_fprintf(stderr
, "ads_find_printer_on_server: %s\n", ads_errstr(rc
));
1708 ads_msgfree(ads
, res
);
1713 if (ads_count_replies(ads
, res
) == 0) {
1714 d_fprintf(stderr
, "Printer '%s' not found\n", argv
[1]);
1715 ads_msgfree(ads
, res
);
1720 prt_dn
= ads_get_dn(ads
, res
);
1721 ads_msgfree(ads
, res
);
1722 rc
= ads_del_dn(ads
, prt_dn
);
1723 ads_memfree(ads
, prt_dn
);
1725 if (!ADS_ERR_OK(rc
)) {
1726 d_fprintf(stderr
, "ads_del_dn: %s\n", ads_errstr(rc
));
1735 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
1737 struct functable func
[] = {
1740 net_ads_printer_search
,
1742 "Search for a printer",
1743 "net ads printer search\n"
1744 " Search for a printer"
1748 net_ads_printer_info
,
1750 "Display printer information",
1751 "net ads printer info\n"
1752 " Display printer information"
1756 net_ads_printer_publish
,
1758 "Publish a printer",
1759 "net ads printer publish\n"
1760 " Publish a printer"
1764 net_ads_printer_remove
,
1767 "net ads printer remove\n"
1770 {NULL
, NULL
, 0, NULL
, NULL
}
1773 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
1777 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
1780 const char *auth_principal
= c
->opt_user_name
;
1781 const char *auth_password
= c
->opt_password
;
1783 char *new_password
= NULL
;
1788 if (c
->display_usage
) {
1790 "net ads password <username>\n"
1791 " Change password for user\n"
1792 " username\tName of user to change password for\n");
1796 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
1797 d_fprintf(stderr
, "You must supply an administrator username/password\n");
1802 d_fprintf(stderr
, "ERROR: You must say which username to change password for\n");
1807 if (!strchr_m(user
, '@')) {
1808 asprintf(&chr
, "%s@%s", argv
[0], lp_realm());
1812 use_in_memory_ccache();
1813 chr
= strchr_m(auth_principal
, '@');
1820 /* use the realm so we can eventually change passwords for users
1821 in realms other than default */
1822 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
1826 /* we don't actually need a full connect, but it's the easy way to
1827 fill in the KDC's addresss */
1830 if (!ads
->config
.realm
) {
1831 d_fprintf(stderr
, "Didn't find the kerberos server!\n");
1836 new_password
= (char *)argv
[1];
1838 asprintf(&prompt
, "Enter new password for %s:", user
);
1839 new_password
= getpass(prompt
);
1843 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
1844 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
1845 if (!ADS_ERR_OK(ret
)) {
1846 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1851 d_printf("Password change for %s completed.\n", user
);
1857 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
1860 char *host_principal
;
1864 if (c
->display_usage
) {
1866 "net ads changetrustpw\n"
1867 " Change the machine account's trust password\n");
1871 if (!secrets_init()) {
1872 DEBUG(1,("Failed to initialise secrets database\n"));
1876 net_use_krb_machine_account(c
);
1878 use_in_memory_ccache();
1880 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1884 fstrcpy(my_name
, global_myname());
1885 strlower_m(my_name
);
1886 asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
);
1887 d_printf("Changing password for principal: %s\n", host_principal
);
1889 ret
= ads_change_trust_account_password(ads
, host_principal
);
1891 if (!ADS_ERR_OK(ret
)) {
1892 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1894 SAFE_FREE(host_principal
);
1898 d_printf("Password change for principal %s succeeded.\n", host_principal
);
1900 if (lp_use_kerberos_keytab()) {
1901 d_printf("Attempting to update system keytab with new password.\n");
1902 if (ads_keytab_create_default(ads
)) {
1903 d_printf("Failed to update system keytab.\n");
1908 SAFE_FREE(host_principal
);
1914 help for net ads search
1916 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
1919 "\nnet ads search <expression> <attributes...>\n"
1920 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1921 "The expression is a standard LDAP search expression, and the\n"
1922 "attributes are a list of LDAP fields to show in the results.\n\n"
1923 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1925 net_common_flags_usage(c
, argc
, argv
);
1931 general ADS search function. Useful in diagnosing problems in ADS
1933 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
1937 const char *ldap_exp
;
1939 LDAPMessage
*res
= NULL
;
1941 if (argc
< 1 || c
->display_usage
) {
1942 return net_ads_search_usage(c
, argc
, argv
);
1945 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1952 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
1954 ldap_exp
, attrs
, &res
);
1955 if (!ADS_ERR_OK(rc
)) {
1956 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
1961 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
1963 /* dump the results */
1966 ads_msgfree(ads
, res
);
1974 help for net ads search
1976 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
1979 "\nnet ads dn <dn> <attributes...>\n"
1980 "\nperform a raw LDAP search on a ADS server and dump the results\n"
1981 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
1982 "to show in the results\n\n"
1983 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1984 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1986 net_common_flags_usage(c
, argc
, argv
);
1992 general ADS search function. Useful in diagnosing problems in ADS
1994 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
2000 LDAPMessage
*res
= NULL
;
2002 if (argc
< 1 || c
->display_usage
) {
2003 return net_ads_dn_usage(c
, argc
, argv
);
2006 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2013 rc
= ads_do_search_all(ads
, dn
,
2015 "(objectclass=*)", attrs
, &res
);
2016 if (!ADS_ERR_OK(rc
)) {
2017 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
2022 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2024 /* dump the results */
2027 ads_msgfree(ads
, res
);
2034 help for net ads sid search
2036 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2039 "\nnet ads sid <sid> <attributes...>\n"
2040 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2041 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2042 "to show in the results\n\n"
2043 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2045 net_common_flags_usage(c
, argc
, argv
);
2051 general ADS search function. Useful in diagnosing problems in ADS
2053 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2057 const char *sid_string
;
2059 LDAPMessage
*res
= NULL
;
2062 if (argc
< 1 || c
->display_usage
) {
2063 return net_ads_sid_usage(c
, argc
, argv
);
2066 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2070 sid_string
= argv
[0];
2073 if (!string_to_sid(&sid
, sid_string
)) {
2074 d_fprintf(stderr
, "could not convert sid\n");
2079 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2080 if (!ADS_ERR_OK(rc
)) {
2081 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
2086 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2088 /* dump the results */
2091 ads_msgfree(ads
, res
);
2097 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2102 if (c
->display_usage
) {
2104 "net ads keytab flush\n"
2105 " Delete the whole keytab\n");
2109 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2112 ret
= ads_keytab_flush(ads
);
2117 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2123 if (c
->display_usage
) {
2125 "net ads keytab add <principal> [principal ...]\n"
2126 " Add principals to local keytab\n"
2127 " principal\tKerberos principal to add to "
2132 d_printf("Processing principals to add...\n");
2133 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2136 for (i
= 0; i
< argc
; i
++) {
2137 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2143 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2148 if (c
->display_usage
) {
2150 "net ads keytab create\n"
2151 " Create new default keytab\n");
2155 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2158 ret
= ads_keytab_create_default(ads
);
2163 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2165 const char *keytab
= NULL
;
2167 if (c
->display_usage
) {
2169 "net ads keytab list [keytab]\n"
2170 " List a local keytab\n"
2171 " keytab\tKeytab to list\n");
2179 return ads_keytab_list(keytab
);
2183 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2185 struct functable func
[] = {
2190 "Add a service principal",
2191 "net ads keytab add\n"
2192 " Add a service principal"
2196 net_ads_keytab_create
,
2198 "Create a fresh keytab",
2199 "net ads keytab create\n"
2200 " Create a fresh keytab"
2204 net_ads_keytab_flush
,
2206 "Remove all keytab entries",
2207 "net ads keytab flush\n"
2208 " Remove all keytab entries"
2212 net_ads_keytab_list
,
2215 "net ads keytab list\n"
2218 {NULL
, NULL
, 0, NULL
, NULL
}
2221 if (!lp_use_kerberos_keytab()) {
2222 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2223 use keytab functions.\n");
2226 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2229 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2233 if (c
->display_usage
) {
2235 "net ads kerberos renew\n"
2236 " Renew TGT from existing credential cache\n");
2240 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2242 d_printf("failed to renew kerberos ticket: %s\n",
2243 error_message(ret
));
2248 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2250 struct PAC_DATA
*pac
= NULL
;
2251 struct PAC_LOGON_INFO
*info
= NULL
;
2252 TALLOC_CTX
*mem_ctx
= NULL
;
2256 if (c
->display_usage
) {
2258 "net ads kerberos pac\n"
2259 " Dump the Kerberos PAC\n");
2263 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2268 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2270 status
= kerberos_return_pac(mem_ctx
,
2279 2592000, /* one month */
2281 if (!NT_STATUS_IS_OK(status
)) {
2282 d_printf("failed to query kerberos PAC: %s\n",
2287 info
= get_logon_info_from_pac(pac
);
2290 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2291 d_printf("The Pac: %s\n", s
);
2296 TALLOC_FREE(mem_ctx
);
2300 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2302 TALLOC_CTX
*mem_ctx
= NULL
;
2306 if (c
->display_usage
) {
2308 "net ads kerberos kinit\n"
2309 " Get Ticket Granting Ticket (TGT) for the user\n");
2313 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2318 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2320 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2328 2592000, /* one month */
2331 d_printf("failed to kinit password: %s\n",
2338 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2340 struct functable func
[] = {
2343 net_ads_kerberos_kinit
,
2345 "Retrieve Ticket Granting Ticket (TGT)",
2346 "net ads kerberos kinit\n"
2347 " Receive Ticket Granting Ticket (TGT)"
2351 net_ads_kerberos_renew
,
2353 "Renew Ticket Granting Ticket from credential cache"
2354 "net ads kerberos renew\n"
2355 " Renew Ticket Granting Ticket from credential cache"
2359 net_ads_kerberos_pac
,
2361 "Dump Kerberos PAC",
2362 "net ads kerberos pac\n"
2363 " Dump Kerberos PAC"
2365 {NULL
, NULL
, 0, NULL
, NULL
}
2368 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2371 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2373 struct functable func
[] = {
2378 "Display details on remote ADS server",
2380 " Display details on remote ADS server"
2386 "Join the local machine to ADS realm",
2388 " Join the local machine to ADS realm"
2394 "Validate machine account",
2395 "net ads testjoin\n"
2396 " Validate machine account"
2402 "Remove the local machine from ADS",
2404 " Remove the local machine from ADS"
2410 "Display machine account details",
2412 " Display machine account details"
2418 "List/modify users",
2420 " List/modify users"
2426 "List/modify groups",
2428 " List/modify groups"
2434 "Issue dynamic DNS update",
2436 " Issue dynamic DNS update"
2442 "Change user passwords",
2443 "net ads password\n"
2444 " Change user passwords"
2448 net_ads_changetrustpw
,
2450 "Change trust account password",
2451 "net ads changetrustpw\n"
2452 " Change trust account password"
2458 "List/modify printer entries",
2460 " List/modify printer entries"
2466 "Issue LDAP search using filter",
2468 " Issue LDAP search using filter"
2474 "Issue LDAP search by DN",
2476 " Issue LDAP search by DN"
2482 "Issue LDAP search by SID",
2484 " Issue LDAP search by SID"
2490 "Display workgroup name",
2491 "net ads workgroup\n"
2492 " Display the workgroup name"
2498 "Perfom CLDAP query on DC",
2500 " Find the ADS DC using CLDAP lookups"
2506 "Manage local keytab file",
2508 " Manage local keytab file"
2514 "Manage group policy objects",
2516 " Manage group policy objects"
2522 "Manage kerberos keytab",
2523 "net ads kerberos\n"
2524 " Manage kerberos keytab"
2526 {NULL
, NULL
, 0, NULL
, NULL
}
2529 return net_run_function(c
, argc
, argv
, "net ads", func
);
2534 static int net_ads_noads(void)
2536 d_fprintf(stderr
, "ADS support not compiled in\n");
2540 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2542 return net_ads_noads();
2545 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2547 return net_ads_noads();
2550 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2552 return net_ads_noads();
2555 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2557 return net_ads_noads();
2560 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2562 return net_ads_noads();
2565 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2567 return net_ads_noads();
2570 /* this one shouldn't display a message */
2571 int net_ads_check(struct net_context
*c
)
2576 int net_ads_check_our_domain(struct net_context
*c
)
2581 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2583 return net_ads_noads();
2586 #endif /* WITH_ADS */