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 nbt_cldap_netlogon_5 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: ");
59 case SAMLOGON_AD_UNK_R
:
60 d_printf("SAMLOGON\n");
63 d_printf("SAMLOGON_USER\n");
66 d_printf("0x%x\n", reply
.type
);
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 nbt_cldap_netlogon_5 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 use_in_memory_ccache();
884 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
885 if (!W_ERROR_IS_OK(werr
)) {
886 d_fprintf(stderr
, "Could not initialise unjoin context.\n");
891 r
->in
.dc_name
= c
->opt_host
;
892 r
->in
.domain_name
= lp_realm();
893 r
->in
.admin_account
= c
->opt_user_name
;
894 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
895 r
->in
.modify_config
= lp_config_backend_is_registry();
896 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
897 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
899 werr
= libnet_Unjoin(ctx
, r
);
900 if (!W_ERROR_IS_OK(werr
)) {
901 d_printf("Failed to leave domain: %s\n",
902 r
->out
.error_string
? r
->out
.error_string
:
903 get_friendly_werror_msg(werr
));
907 if (W_ERROR_IS_OK(werr
)) {
908 d_printf("Deleted account for '%s' in realm '%s'\n",
909 r
->in
.machine_name
, r
->out
.dns_domain_name
);
913 /* We couldn't delete it - see if the disable succeeded. */
914 if (r
->out
.disabled_machine_account
) {
915 d_printf("Disabled account for '%s' in realm '%s'\n",
916 r
->in
.machine_name
, r
->out
.dns_domain_name
);
921 d_fprintf(stderr
, "Failed to disable machine account for '%s' in realm '%s'\n",
922 r
->in
.machine_name
, r
->out
.dns_domain_name
);
928 if (W_ERROR_IS_OK(werr
)) {
935 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
937 ADS_STRUCT
*ads
= NULL
;
940 if (!secrets_init()) {
941 DEBUG(1,("Failed to initialise secrets database\n"));
942 return NT_STATUS_ACCESS_DENIED
;
945 net_use_krb_machine_account(c
);
947 status
= ads_startup(c
, true, &ads
);
948 if (!ADS_ERR_OK(status
)) {
949 return ads_ntstatus(status
);
957 check that an existing join is OK
959 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
962 use_in_memory_ccache();
964 if (c
->display_usage
) {
967 " Test if the existing join is ok\n");
971 /* Display success or failure */
972 status
= net_ads_join_ok(c
);
973 if (!NT_STATUS_IS_OK(status
)) {
974 fprintf(stderr
,"Join to domain is not valid: %s\n",
975 get_friendly_nt_error_msg(status
));
979 printf("Join is OK\n");
983 /*******************************************************************
984 Simple configu checks before beginning the join
985 ********************************************************************/
987 static WERROR
check_ads_config( void )
989 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
990 d_printf("Host is not configured as a member server.\n");
991 return WERR_INVALID_DOMAIN_ROLE
;
994 if (strlen(global_myname()) > 15) {
995 d_printf("Our netbios name can be at most 15 chars long, "
996 "\"%s\" is %u chars long\n", global_myname(),
997 (unsigned int)strlen(global_myname()));
998 return WERR_INVALID_COMPUTER_NAME
;
1001 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1002 d_fprintf(stderr
, "realm must be set in in %s for ADS "
1003 "join to succeed.\n", get_dyn_CONFIGFILE());
1004 return WERR_INVALID_PARAM
;
1010 /*******************************************************************
1011 Send a DNS update request
1012 *******************************************************************/
1014 #if defined(WITH_DNS_UPDATES)
1016 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
1017 const char *pszDomainName
, const char *pszHostName
,
1018 const struct sockaddr_storage
*sslist
,
1021 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1022 const char *machine_name
,
1023 const struct sockaddr_storage
*addrs
,
1026 struct dns_rr_ns
*nameservers
= NULL
;
1028 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1031 const char *dnsdomain
= NULL
;
1032 char *root_domain
= NULL
;
1034 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1035 d_printf("No DNS domain configured for %s. "
1036 "Unable to perform DNS Update.\n", machine_name
);
1037 status
= NT_STATUS_INVALID_PARAMETER
;
1042 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
1043 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1044 /* Child domains often do not have NS records. Look
1045 for the NS record for the forest root domain
1046 (rootDomainNamingContext in therootDSE) */
1048 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1049 LDAPMessage
*msg
= NULL
;
1051 ADS_STATUS ads_status
;
1053 if ( !ads
->ldap
.ld
) {
1054 ads_status
= ads_connect( ads
);
1055 if ( !ADS_ERR_OK(ads_status
) ) {
1056 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1061 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1062 "(objectclass=*)", rootname_attrs
, &msg
);
1063 if (!ADS_ERR_OK(ads_status
)) {
1067 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1069 ads_msgfree( ads
, msg
);
1073 root_domain
= ads_build_domain( root_dn
);
1076 ads_msgfree( ads
, msg
);
1078 /* try again for NS servers */
1080 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1082 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1083 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1084 "realm\n", ads
->config
.realm
));
1088 dnsdomain
= root_domain
;
1092 /* Now perform the dns update - we'll try non-secure and if we fail,
1093 we'll follow it up with a secure update */
1095 fstrcpy( dns_server
, nameservers
[0].hostname
);
1097 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1098 if (!ERR_DNS_IS_OK(dns_err
)) {
1099 status
= NT_STATUS_UNSUCCESSFUL
;
1104 SAFE_FREE( root_domain
);
1109 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
)
1112 struct sockaddr_storage
*iplist
= NULL
;
1113 fstring machine_name
;
1116 name_to_fqdn( machine_name
, global_myname() );
1117 strlower_m( machine_name
);
1119 /* Get our ip address (not the 127.0.0.x address but a real ip
1122 num_addrs
= get_my_ip_address( &iplist
);
1123 if ( num_addrs
<= 0 ) {
1124 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1126 return NT_STATUS_INVALID_PARAMETER
;
1129 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1131 SAFE_FREE( iplist
);
1137 /*******************************************************************
1138 ********************************************************************/
1140 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1142 d_printf("net ads join [options]\n");
1143 d_printf("Valid options:\n");
1144 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1145 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1146 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1147 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1148 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1149 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1150 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1151 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1152 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1153 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1154 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1155 d_printf(" the two other attributes.\n");
1160 /*******************************************************************
1161 ********************************************************************/
1163 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1165 TALLOC_CTX
*ctx
= NULL
;
1166 struct libnet_JoinCtx
*r
= NULL
;
1167 const char *domain
= lp_realm();
1168 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1169 bool createupn
= false;
1170 const char *machineupn
= NULL
;
1171 const char *create_in_ou
= NULL
;
1173 const char *os_name
= NULL
;
1174 const char *os_version
= NULL
;
1175 bool modify_config
= lp_config_backend_is_registry();
1177 if (c
->display_usage
)
1178 return net_ads_join_usage(c
, argc
, argv
);
1180 if (!modify_config
) {
1182 werr
= check_ads_config();
1183 if (!W_ERROR_IS_OK(werr
)) {
1184 d_fprintf(stderr
, "Invalid configuration. Exiting....\n");
1189 if (!(ctx
= talloc_init("net_ads_join"))) {
1190 d_fprintf(stderr
, "Could not initialise talloc context.\n");
1195 use_in_memory_ccache();
1197 werr
= libnet_init_JoinCtx(ctx
, &r
);
1198 if (!W_ERROR_IS_OK(werr
)) {
1202 /* process additional command line args */
1204 for ( i
=0; i
<argc
; i
++ ) {
1205 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1207 machineupn
= get_string_param(argv
[i
]);
1209 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1210 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1211 d_fprintf(stderr
, "Please supply a valid OU path.\n");
1212 werr
= WERR_INVALID_PARAM
;
1216 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1217 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1218 d_fprintf(stderr
, "Please supply a operating system name.\n");
1219 werr
= WERR_INVALID_PARAM
;
1223 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1224 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1225 d_fprintf(stderr
, "Please supply a valid operating system version.\n");
1226 werr
= WERR_INVALID_PARAM
;
1236 d_fprintf(stderr
, "Please supply a valid domain name\n");
1237 werr
= WERR_INVALID_PARAM
;
1241 /* Do the domain join here */
1243 r
->in
.domain_name
= domain
;
1244 r
->in
.create_upn
= createupn
;
1245 r
->in
.upn
= machineupn
;
1246 r
->in
.account_ou
= create_in_ou
;
1247 r
->in
.os_name
= os_name
;
1248 r
->in
.os_version
= os_version
;
1249 r
->in
.dc_name
= c
->opt_host
;
1250 r
->in
.admin_account
= c
->opt_user_name
;
1251 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1253 r
->in
.modify_config
= modify_config
;
1254 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1255 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1256 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1258 werr
= libnet_Join(ctx
, r
);
1259 if (!W_ERROR_IS_OK(werr
)) {
1263 /* Check the short name of the domain */
1265 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1266 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1267 d_printf("domain name obtained from the server.\n");
1268 d_printf("Using the name [%s] from the server.\n", r
->out
.netbios_domain_name
);
1269 d_printf("You should set \"workgroup = %s\" in %s.\n",
1270 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1273 d_printf("Using short domain name -- %s\n", r
->out
.netbios_domain_name
);
1275 if (r
->out
.dns_domain_name
) {
1276 d_printf("Joined '%s' to realm '%s'\n", r
->in
.machine_name
,
1277 r
->out
.dns_domain_name
);
1279 d_printf("Joined '%s' to domain '%s'\n", r
->in
.machine_name
,
1280 r
->out
.netbios_domain_name
);
1283 #if defined(WITH_DNS_UPDATES)
1284 if (r
->out
.domain_is_ad
) {
1285 /* We enter this block with user creds */
1286 ADS_STRUCT
*ads_dns
= NULL
;
1288 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1289 /* kinit with the machine password */
1291 use_in_memory_ccache();
1292 asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname() );
1293 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1294 r
->out
.netbios_domain_name
, NULL
, NULL
);
1295 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1296 strupper_m(ads_dns
->auth
.realm
);
1297 ads_kinit_password( ads_dns
);
1300 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns( ctx
, ads_dns
)) ) {
1301 d_fprintf( stderr
, "DNS update failed!\n" );
1304 /* exit from this block using machine creds */
1305 ads_destroy(&ads_dns
);
1314 /* issue an overall failure message at the end. */
1315 d_printf("Failed to join domain: %s\n",
1316 r
&& r
->out
.error_string
? r
->out
.error_string
:
1317 get_friendly_werror_msg(werr
));
1323 /*******************************************************************
1324 ********************************************************************/
1326 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1328 #if defined(WITH_DNS_UPDATES)
1334 talloc_enable_leak_report();
1337 if (argc
> 0 || c
->display_usage
) {
1339 "net ads dns register\n"
1340 " Register hostname with DNS\n");
1344 if (!(ctx
= talloc_init("net_ads_dns"))) {
1345 d_fprintf(stderr
, "Could not initialise talloc context\n");
1349 status
= ads_startup(c
, true, &ads
);
1350 if ( !ADS_ERR_OK(status
) ) {
1351 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1356 if ( !NT_STATUS_IS_OK(net_update_dns(ctx
, ads
)) ) {
1357 d_fprintf( stderr
, "DNS update failed!\n" );
1358 ads_destroy( &ads
);
1363 d_fprintf( stderr
, "Successfully registered hostname with DNS\n" );
1370 d_fprintf(stderr
, "DNS update support not enabled at compile time!\n");
1375 #if defined(WITH_DNS_UPDATES)
1376 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1379 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1381 #if defined(WITH_DNS_UPDATES)
1385 talloc_enable_leak_report();
1388 if (argc
!= 2 || c
->display_usage
) {
1390 "net ads dns gethostbyname <server> <name>\n"
1391 " Look up hostname from the AD\n"
1392 " server\tName server to use\n"
1393 " name\tName to look up\n");
1397 err
= do_gethostbyname(argv
[0], argv
[1]);
1399 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err
));
1404 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1406 struct functable func
[] = {
1409 net_ads_dns_register
,
1411 "Add host dns entry to AD",
1412 "net ads dns register\n"
1413 " Add host dns entry to AD"
1417 net_ads_dns_gethostbyname
,
1420 "net ads dns gethostbyname\n"
1423 {NULL
, NULL
, 0, NULL
, NULL
}
1426 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1429 /*******************************************************************
1430 ********************************************************************/
1432 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1435 "\nnet ads printer search <printer>"
1436 "\n\tsearch for a printer in the directory\n"
1437 "\nnet ads printer info <printer> <server>"
1438 "\n\tlookup info in directory for printer on server"
1439 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1440 "\nnet ads printer publish <printername>"
1441 "\n\tpublish printer in directory"
1442 "\n\t(note: printer name is required)\n"
1443 "\nnet ads printer remove <printername>"
1444 "\n\tremove printer from directory"
1445 "\n\t(note: printer name is required)\n");
1449 /*******************************************************************
1450 ********************************************************************/
1452 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1456 LDAPMessage
*res
= NULL
;
1458 if (c
->display_usage
) {
1460 "net ads printer search\n"
1461 " List printers in the AD\n");
1465 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1469 rc
= ads_find_printers(ads
, &res
);
1471 if (!ADS_ERR_OK(rc
)) {
1472 d_fprintf(stderr
, "ads_find_printer: %s\n", ads_errstr(rc
));
1473 ads_msgfree(ads
, res
);
1478 if (ads_count_replies(ads
, res
) == 0) {
1479 d_fprintf(stderr
, "No results found\n");
1480 ads_msgfree(ads
, res
);
1486 ads_msgfree(ads
, res
);
1491 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1495 const char *servername
, *printername
;
1496 LDAPMessage
*res
= NULL
;
1498 if (c
->display_usage
) {
1500 "net ads printer info [printername [servername]]\n"
1501 " Display printer info from AD\n"
1502 " printername\tPrinter name or wildcard\n"
1503 " servername\tName of the print server\n");
1507 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1512 printername
= argv
[0];
1518 servername
= argv
[1];
1520 servername
= global_myname();
1523 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1525 if (!ADS_ERR_OK(rc
)) {
1526 d_fprintf(stderr
, "Server '%s' not found: %s\n",
1527 servername
, ads_errstr(rc
));
1528 ads_msgfree(ads
, res
);
1533 if (ads_count_replies(ads
, res
) == 0) {
1534 d_fprintf(stderr
, "Printer '%s' not found\n", printername
);
1535 ads_msgfree(ads
, res
);
1541 ads_msgfree(ads
, res
);
1547 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1551 const char *servername
, *printername
;
1552 struct cli_state
*cli
;
1553 struct rpc_pipe_client
*pipe_hnd
;
1554 struct sockaddr_storage server_ss
;
1556 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1557 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1558 char *prt_dn
, *srv_dn
, **srv_cn
;
1559 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1560 LDAPMessage
*res
= NULL
;
1562 if (argc
< 1 || c
->display_usage
) {
1564 "net ads printer publish <printername> [servername]\n"
1565 " Publish printer in AD\n"
1566 " printername\tName of the printer\n"
1567 " servername\tName of the print server\n");
1568 talloc_destroy(mem_ctx
);
1572 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1573 talloc_destroy(mem_ctx
);
1577 printername
= argv
[0];
1580 servername
= argv
[1];
1582 servername
= global_myname();
1585 /* Get printer data from SPOOLSS */
1587 resolve_name(servername
, &server_ss
, 0x20);
1589 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1592 c
->opt_user_name
, c
->opt_workgroup
,
1593 c
->opt_password
? c
->opt_password
: "",
1594 CLI_FULL_CONNECTION_USE_KERBEROS
,
1597 if (NT_STATUS_IS_ERR(nt_status
)) {
1598 d_fprintf(stderr
, "Unable to open a connnection to %s to obtain data "
1599 "for %s\n", servername
, printername
);
1601 talloc_destroy(mem_ctx
);
1605 /* Publish on AD server */
1607 ads_find_machine_acct(ads
, &res
, servername
);
1609 if (ads_count_replies(ads
, res
) == 0) {
1610 d_fprintf(stderr
, "Could not find machine account for server %s\n",
1613 talloc_destroy(mem_ctx
);
1617 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1618 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1620 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1621 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1622 if (!srv_cn_escaped
|| !printername_escaped
) {
1623 SAFE_FREE(srv_cn_escaped
);
1624 SAFE_FREE(printername_escaped
);
1625 d_fprintf(stderr
, "Internal error, out of memory!");
1627 talloc_destroy(mem_ctx
);
1631 asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
);
1633 SAFE_FREE(srv_cn_escaped
);
1634 SAFE_FREE(printername_escaped
);
1636 pipe_hnd
= cli_rpc_pipe_open_noauth(cli
, PI_SPOOLSS
, &nt_status
);
1638 d_fprintf(stderr
, "Unable to open a connnection to the spoolss pipe on %s\n",
1642 talloc_destroy(mem_ctx
);
1646 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1650 talloc_destroy(mem_ctx
);
1654 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1655 if (!ADS_ERR_OK(rc
)) {
1656 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1659 talloc_destroy(mem_ctx
);
1663 d_printf("published printer\n");
1666 talloc_destroy(mem_ctx
);
1671 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1675 const char *servername
;
1677 LDAPMessage
*res
= NULL
;
1679 if (argc
< 1 || c
->display_usage
) {
1681 "net ads printer remove <printername> [servername]\n"
1682 " Remove a printer from the AD\n"
1683 " printername\tName of the printer\n"
1684 " servername\tName of the print server\n");
1688 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1693 servername
= argv
[1];
1695 servername
= global_myname();
1698 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1700 if (!ADS_ERR_OK(rc
)) {
1701 d_fprintf(stderr
, "ads_find_printer_on_server: %s\n", ads_errstr(rc
));
1702 ads_msgfree(ads
, res
);
1707 if (ads_count_replies(ads
, res
) == 0) {
1708 d_fprintf(stderr
, "Printer '%s' not found\n", argv
[1]);
1709 ads_msgfree(ads
, res
);
1714 prt_dn
= ads_get_dn(ads
, res
);
1715 ads_msgfree(ads
, res
);
1716 rc
= ads_del_dn(ads
, prt_dn
);
1717 ads_memfree(ads
, prt_dn
);
1719 if (!ADS_ERR_OK(rc
)) {
1720 d_fprintf(stderr
, "ads_del_dn: %s\n", ads_errstr(rc
));
1729 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
1731 struct functable func
[] = {
1734 net_ads_printer_search
,
1736 "Search for a printer",
1737 "net ads printer search\n"
1738 " Search for a printer"
1742 net_ads_printer_info
,
1744 "Display printer information",
1745 "net ads printer info\n"
1746 " Display printer information"
1750 net_ads_printer_publish
,
1752 "Publish a printer",
1753 "net ads printer publish\n"
1754 " Publish a printer"
1758 net_ads_printer_remove
,
1761 "net ads printer remove\n"
1764 {NULL
, NULL
, 0, NULL
, NULL
}
1767 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
1771 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
1774 const char *auth_principal
= c
->opt_user_name
;
1775 const char *auth_password
= c
->opt_password
;
1777 char *new_password
= NULL
;
1782 if (c
->display_usage
) {
1784 "net ads password <username>\n"
1785 " Change password for user\n"
1786 " username\tName of user to change password for\n");
1790 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
1791 d_fprintf(stderr
, "You must supply an administrator username/password\n");
1796 d_fprintf(stderr
, "ERROR: You must say which username to change password for\n");
1801 if (!strchr_m(user
, '@')) {
1802 asprintf(&chr
, "%s@%s", argv
[0], lp_realm());
1806 use_in_memory_ccache();
1807 chr
= strchr_m(auth_principal
, '@');
1814 /* use the realm so we can eventually change passwords for users
1815 in realms other than default */
1816 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
1820 /* we don't actually need a full connect, but it's the easy way to
1821 fill in the KDC's addresss */
1824 if (!ads
->config
.realm
) {
1825 d_fprintf(stderr
, "Didn't find the kerberos server!\n");
1830 new_password
= (char *)argv
[1];
1832 asprintf(&prompt
, "Enter new password for %s:", user
);
1833 new_password
= getpass(prompt
);
1837 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
1838 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
1839 if (!ADS_ERR_OK(ret
)) {
1840 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1845 d_printf("Password change for %s completed.\n", user
);
1851 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
1854 char *host_principal
;
1858 if (c
->display_usage
) {
1860 "net ads changetrustpw\n"
1861 " Change the machine account's trust password\n");
1865 if (!secrets_init()) {
1866 DEBUG(1,("Failed to initialise secrets database\n"));
1870 net_use_krb_machine_account(c
);
1872 use_in_memory_ccache();
1874 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1878 fstrcpy(my_name
, global_myname());
1879 strlower_m(my_name
);
1880 asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
);
1881 d_printf("Changing password for principal: %s\n", host_principal
);
1883 ret
= ads_change_trust_account_password(ads
, host_principal
);
1885 if (!ADS_ERR_OK(ret
)) {
1886 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1888 SAFE_FREE(host_principal
);
1892 d_printf("Password change for principal %s succeeded.\n", host_principal
);
1894 if (lp_use_kerberos_keytab()) {
1895 d_printf("Attempting to update system keytab with new password.\n");
1896 if (ads_keytab_create_default(ads
)) {
1897 d_printf("Failed to update system keytab.\n");
1902 SAFE_FREE(host_principal
);
1908 help for net ads search
1910 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
1913 "\nnet ads search <expression> <attributes...>\n"
1914 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1915 "The expression is a standard LDAP search expression, and the\n"
1916 "attributes are a list of LDAP fields to show in the results.\n\n"
1917 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1919 net_common_flags_usage(c
, argc
, argv
);
1925 general ADS search function. Useful in diagnosing problems in ADS
1927 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
1931 const char *ldap_exp
;
1933 LDAPMessage
*res
= NULL
;
1935 if (argc
< 1 || c
->display_usage
) {
1936 return net_ads_search_usage(c
, argc
, argv
);
1939 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1946 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
1948 ldap_exp
, attrs
, &res
);
1949 if (!ADS_ERR_OK(rc
)) {
1950 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
1955 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
1957 /* dump the results */
1960 ads_msgfree(ads
, res
);
1968 help for net ads search
1970 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
1973 "\nnet ads dn <dn> <attributes...>\n"
1974 "\nperform a raw LDAP search on a ADS server and dump the results\n"
1975 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
1976 "to show in the results\n\n"
1977 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1978 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1980 net_common_flags_usage(c
, argc
, argv
);
1986 general ADS search function. Useful in diagnosing problems in ADS
1988 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
1994 LDAPMessage
*res
= NULL
;
1996 if (argc
< 1 || c
->display_usage
) {
1997 return net_ads_dn_usage(c
, argc
, argv
);
2000 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2007 rc
= ads_do_search_all(ads
, dn
,
2009 "(objectclass=*)", attrs
, &res
);
2010 if (!ADS_ERR_OK(rc
)) {
2011 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
2016 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2018 /* dump the results */
2021 ads_msgfree(ads
, res
);
2028 help for net ads sid search
2030 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2033 "\nnet ads sid <sid> <attributes...>\n"
2034 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2035 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2036 "to show in the results\n\n"
2037 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2039 net_common_flags_usage(c
, argc
, argv
);
2045 general ADS search function. Useful in diagnosing problems in ADS
2047 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2051 const char *sid_string
;
2053 LDAPMessage
*res
= NULL
;
2056 if (argc
< 1 || c
->display_usage
) {
2057 return net_ads_sid_usage(c
, argc
, argv
);
2060 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2064 sid_string
= argv
[0];
2067 if (!string_to_sid(&sid
, sid_string
)) {
2068 d_fprintf(stderr
, "could not convert sid\n");
2073 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2074 if (!ADS_ERR_OK(rc
)) {
2075 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
2080 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2082 /* dump the results */
2085 ads_msgfree(ads
, res
);
2091 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2096 if (c
->display_usage
) {
2098 "net ads keytab flush\n"
2099 " Delete the whole keytab\n");
2103 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2106 ret
= ads_keytab_flush(ads
);
2111 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2117 if (c
->display_usage
) {
2119 "net ads keytab add <principal> [principal ...]\n"
2120 " Add principals to local keytab\n"
2121 " principal\tKerberos principal to add to "
2126 d_printf("Processing principals to add...\n");
2127 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2130 for (i
= 0; i
< argc
; i
++) {
2131 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2137 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2142 if (c
->display_usage
) {
2144 "net ads keytab create\n"
2145 " Create new default keytab\n");
2149 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2152 ret
= ads_keytab_create_default(ads
);
2157 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2159 const char *keytab
= NULL
;
2161 if (c
->display_usage
) {
2163 "net ads keytab list [keytab]\n"
2164 " List a local keytab\n"
2165 " keytab\tKeytab to list\n");
2173 return ads_keytab_list(keytab
);
2177 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2179 struct functable func
[] = {
2184 "Add a service principal",
2185 "net ads keytab add\n"
2186 " Add a service principal"
2190 net_ads_keytab_create
,
2192 "Create a fresh keytab",
2193 "net ads keytab create\n"
2194 " Create a fresh keytab"
2198 net_ads_keytab_flush
,
2200 "Remove all keytab entries",
2201 "net ads keytab flush\n"
2202 " Remove all keytab entries"
2206 net_ads_keytab_list
,
2209 "net ads keytab list\n"
2212 {NULL
, NULL
, 0, NULL
, NULL
}
2215 if (!lp_use_kerberos_keytab()) {
2216 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2217 use keytab functions.\n");
2220 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2223 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2227 if (c
->display_usage
) {
2229 "net ads kerberos renew\n"
2230 " Renew TGT from existing credential cache\n");
2234 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2236 d_printf("failed to renew kerberos ticket: %s\n",
2237 error_message(ret
));
2242 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2244 struct PAC_DATA
*pac
= NULL
;
2245 struct PAC_LOGON_INFO
*info
= NULL
;
2246 TALLOC_CTX
*mem_ctx
= NULL
;
2250 if (c
->display_usage
) {
2252 "net ads kerberos pac\n"
2253 " Dump the Kerberos PAC\n");
2257 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2262 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2264 status
= kerberos_return_pac(mem_ctx
,
2273 2592000, /* one month */
2275 if (!NT_STATUS_IS_OK(status
)) {
2276 d_printf("failed to query kerberos PAC: %s\n",
2281 info
= get_logon_info_from_pac(pac
);
2284 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2285 d_printf("The Pac: %s\n", s
);
2290 TALLOC_FREE(mem_ctx
);
2294 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2296 TALLOC_CTX
*mem_ctx
= NULL
;
2300 if (c
->display_usage
) {
2302 "net ads kerberos kinit\n"
2303 " Get Ticket Granting Ticket (TGT) for the user\n");
2307 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2312 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2314 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2322 2592000, /* one month */
2325 d_printf("failed to kinit password: %s\n",
2332 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2334 struct functable func
[] = {
2337 net_ads_kerberos_kinit
,
2339 "Retrieve Ticket Granting Ticket (TGT)",
2340 "net ads kerberos kinit\n"
2341 " Receive Ticket Granting Ticket (TGT)"
2345 net_ads_kerberos_renew
,
2347 "Renew Ticket Granting Ticket from credential cache"
2348 "net ads kerberos renew\n"
2349 " Renew Ticket Granting Ticket from credential cache"
2353 net_ads_kerberos_pac
,
2355 "Dump Kerberos PAC",
2356 "net ads kerberos pac\n"
2357 " Dump Kerberos PAC"
2359 {NULL
, NULL
, 0, NULL
, NULL
}
2362 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2365 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2367 struct functable func
[] = {
2372 "Display details on remote ADS server",
2374 " Display details on remote ADS server"
2380 "Join the local machine to ADS realm",
2382 " Join the local machine to ADS realm"
2388 "Validate machine account",
2389 "net ads testjoin\n"
2390 " Validate machine account"
2396 "Remove the local machine from ADS",
2398 " Remove the local machine from ADS"
2404 "Display machine account details",
2406 " Display machine account details"
2412 "List/modify users",
2414 " List/modify users"
2420 "List/modify groups",
2422 " List/modify groups"
2428 "Issue dynamic DNS update",
2430 " Issue dynamic DNS update"
2436 "Change user passwords",
2437 "net ads password\n"
2438 " Change user passwords"
2442 net_ads_changetrustpw
,
2444 "Change trust account password",
2445 "net ads changetrustpw\n"
2446 " Change trust account password"
2452 "List/modify printer entries",
2454 " List/modify printer entries"
2460 "Issue LDAP search using filter",
2462 " Issue LDAP search using filter"
2468 "Issue LDAP search by DN",
2470 " Issue LDAP search by DN"
2476 "Issue LDAP search by SID",
2478 " Issue LDAP search by SID"
2484 "Display workgroup name",
2485 "net ads workgroup\n"
2486 " Display the workgroup name"
2492 "Perfom CLDAP query on DC",
2494 " Find the ADS DC using CLDAP lookups"
2500 "Manage local keytab file",
2502 " Manage local keytab file"
2508 "Manage group policy objects",
2510 " Manage group policy objects"
2516 "Manage kerberos keytab",
2517 "net ads kerberos\n"
2518 " Manage kerberos keytab"
2520 {NULL
, NULL
, 0, NULL
, NULL
}
2523 return net_run_function(c
, argc
, argv
, "net ads", func
);
2528 static int net_ads_noads(void)
2530 d_fprintf(stderr
, "ADS support not compiled in\n");
2534 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2536 return net_ads_noads();
2539 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2541 return net_ads_noads();
2544 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2546 return net_ads_noads();
2549 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2551 return net_ads_noads();
2554 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2556 return net_ads_noads();
2559 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2561 return net_ads_noads();
2564 /* this one shouldn't display a message */
2565 int net_ads_check(struct net_context
*c
)
2570 int net_ads_check_our_domain(struct net_context
*c
)
2575 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2577 return net_ads_noads();
2580 #endif /* WITH_ADS */