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"
26 #include "libnet/libnet.h"
30 /* when we do not have sufficient input parameters to contact a remote domain
31 * we always fall back to our own realm - Guenther*/
33 static const char *assume_own_realm(struct net_context
*c
)
35 if (!c
->opt_host
&& strequal(lp_workgroup(), c
->opt_target_workgroup
)) {
43 do a cldap netlogon query
45 static int net_ads_cldap_netlogon(struct net_context
*c
, ADS_STRUCT
*ads
)
47 char addr
[INET6_ADDRSTRLEN
];
48 struct nbt_cldap_netlogon_5 reply
;
50 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
51 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
52 d_fprintf(stderr
, "CLDAP query failed!\n");
56 d_printf("Information for Domain Controller: %s\n\n",
59 d_printf("Response Type: ");
61 case SAMLOGON_AD_UNK_R
:
62 d_printf("SAMLOGON\n");
65 d_printf("SAMLOGON_USER\n");
68 d_printf("0x%x\n", reply
.type
);
72 d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), reply
.domain_uuid
));
76 "\tIs a GC of the forest: %s\n"
77 "\tIs an LDAP server: %s\n"
79 "\tIs running a KDC: %s\n"
80 "\tIs running time services: %s\n"
81 "\tIs the closest DC: %s\n"
83 "\tHas a hardware clock: %s\n"
84 "\tIs a non-domain NC serviced by LDAP server: %s\n"
85 "\tIs NT6 DC that has some secrets: %s\n"
86 "\tIs NT6 DC that has all secrets: %s\n",
87 (reply
.server_type
& NBT_SERVER_PDC
) ? "yes" : "no",
88 (reply
.server_type
& NBT_SERVER_GC
) ? "yes" : "no",
89 (reply
.server_type
& NBT_SERVER_LDAP
) ? "yes" : "no",
90 (reply
.server_type
& NBT_SERVER_DS
) ? "yes" : "no",
91 (reply
.server_type
& NBT_SERVER_KDC
) ? "yes" : "no",
92 (reply
.server_type
& NBT_SERVER_TIMESERV
) ? "yes" : "no",
93 (reply
.server_type
& NBT_SERVER_CLOSEST
) ? "yes" : "no",
94 (reply
.server_type
& NBT_SERVER_WRITABLE
) ? "yes" : "no",
95 (reply
.server_type
& NBT_SERVER_GOOD_TIMESERV
) ? "yes" : "no",
96 (reply
.server_type
& NBT_SERVER_NDNC
) ? "yes" : "no",
97 (reply
.server_type
& NBT_SERVER_SELECT_SECRET_DOMAIN_6
) ? "yes" : "no",
98 (reply
.server_type
& NBT_SERVER_FULL_SECRET_DOMAIN_6
) ? "yes" : "no");
101 printf("Forest:\t\t\t%s\n", reply
.forest
);
102 printf("Domain:\t\t\t%s\n", reply
.dns_domain
);
103 printf("Domain Controller:\t%s\n", reply
.pdc_dns_name
);
105 printf("Pre-Win2k Domain:\t%s\n", reply
.domain
);
106 printf("Pre-Win2k Hostname:\t%s\n", reply
.pdc_name
);
108 if (*reply
.user_name
) printf("User name:\t%s\n", reply
.user_name
);
110 printf("Server Site Name :\t\t%s\n", reply
.server_site
);
111 printf("Client Site Name :\t\t%s\n", reply
.client_site
);
113 d_printf("NT Version: %d\n", reply
.nt_version
);
114 d_printf("LMNT Token: %.2x\n", reply
.lmnt_token
);
115 d_printf("LM20 Token: %.2x\n", reply
.lm20_token
);
121 this implements the CLDAP based netlogon lookup requests
122 for finding the domain controller of a ADS domain
124 static int net_ads_lookup(struct net_context
*c
, int argc
, const char **argv
)
128 if (c
->display_usage
) {
131 " Find the ADS DC using CLDAP lookup.\n");
135 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
136 d_fprintf(stderr
, "Didn't find the cldap server!\n");
140 if (!ads
->config
.realm
) {
141 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
142 ads
->ldap
.port
= 389;
145 return net_ads_cldap_netlogon(c
, ads
);
150 static int net_ads_info(struct net_context
*c
, int argc
, const char **argv
)
153 char addr
[INET6_ADDRSTRLEN
];
155 if (c
->display_usage
) {
158 " Display information about an Active Directory "
163 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
164 d_fprintf(stderr
, "Didn't find the ldap server!\n");
168 if (!ads
|| !ads
->config
.realm
) {
169 d_fprintf(stderr
, "Didn't find the ldap server!\n");
173 /* Try to set the server's current time since we didn't do a full
174 TCP LDAP session initially */
176 if ( !ADS_ERR_OK(ads_current_time( ads
)) ) {
177 d_fprintf( stderr
, "Failed to get server's current time!\n");
180 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
182 d_printf("LDAP server: %s\n", addr
);
183 d_printf("LDAP server name: %s\n", ads
->config
.ldap_server_name
);
184 d_printf("Realm: %s\n", ads
->config
.realm
);
185 d_printf("Bind Path: %s\n", ads
->config
.bind_path
);
186 d_printf("LDAP port: %d\n", ads
->ldap
.port
);
187 d_printf("Server time: %s\n", http_timestring(ads
->config
.current_time
));
189 d_printf("KDC server: %s\n", ads
->auth
.kdc_server
);
190 d_printf("Server time offset: %d\n", ads
->auth
.time_offset
);
195 static void use_in_memory_ccache(void) {
196 /* Use in-memory credentials cache so we do not interfere with
197 * existing credentials */
198 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
201 static ADS_STATUS
ads_startup_int(struct net_context
*c
, bool only_own_domain
,
202 uint32 auth_flags
, ADS_STRUCT
**ads_ret
)
204 ADS_STRUCT
*ads
= NULL
;
206 bool need_password
= false;
207 bool second_time
= false;
209 const char *realm
= NULL
;
210 bool tried_closest_dc
= false;
212 /* lp_realm() should be handled by a command line param,
213 However, the join requires that realm be set in smb.conf
214 and compares our realm with the remote server's so this is
215 ok until someone needs more flexibility */
220 if (only_own_domain
) {
223 realm
= assume_own_realm(c
);
226 ads
= ads_init(realm
, c
->opt_target_workgroup
, c
->opt_host
);
228 if (!c
->opt_user_name
) {
229 c
->opt_user_name
= "administrator";
232 if (c
->opt_user_specified
) {
233 need_password
= true;
237 if (!c
->opt_password
&& need_password
&& !c
->opt_machine_pass
) {
238 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
239 if (!c
->opt_password
) {
241 return ADS_ERROR(LDAP_NO_MEMORY
);
245 if (c
->opt_password
) {
246 use_in_memory_ccache();
247 SAFE_FREE(ads
->auth
.password
);
248 ads
->auth
.password
= smb_xstrdup(c
->opt_password
);
251 ads
->auth
.flags
|= auth_flags
;
252 SAFE_FREE(ads
->auth
.user_name
);
253 ads
->auth
.user_name
= smb_xstrdup(c
->opt_user_name
);
256 * If the username is of the form "name@realm",
257 * extract the realm and convert to upper case.
258 * This is only used to establish the connection.
260 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
262 SAFE_FREE(ads
->auth
.realm
);
263 ads
->auth
.realm
= smb_xstrdup(cp
);
264 strupper_m(ads
->auth
.realm
);
267 status
= ads_connect(ads
);
269 if (!ADS_ERR_OK(status
)) {
271 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
272 NT_STATUS_NO_LOGON_SERVERS
)) {
273 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
278 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
279 need_password
= true;
288 /* when contacting our own domain, make sure we use the closest DC.
289 * This is done by reconnecting to ADS because only the first call to
290 * ads_connect will give us our own sitename */
292 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
294 tried_closest_dc
= true; /* avoid loop */
296 if (!ads
->config
.tried_closest_dc
) {
298 namecache_delete(ads
->server
.realm
, 0x1C);
299 namecache_delete(ads
->server
.workgroup
, 0x1C);
312 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
314 return ads_startup_int(c
, only_own_domain
, 0, ads
);
317 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
319 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
323 Check to see if connection can be made via ads.
324 ads_startup() stores the password in opt_password if it needs to so
325 that rpc or rap can use it without re-prompting.
327 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
332 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
336 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
338 status
= ads_connect(ads
);
339 if ( !ADS_ERR_OK(status
) ) {
347 int net_ads_check_our_domain(struct net_context
*c
)
349 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
352 int net_ads_check(struct net_context
*c
)
354 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
358 determine the netbios workgroup name for a domain
360 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
363 char addr
[INET6_ADDRSTRLEN
];
364 struct nbt_cldap_netlogon_5 reply
;
366 if (c
->display_usage
) {
368 "net ads workgroup\n"
369 " Print the workgroup name\n");
373 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
374 d_fprintf(stderr
, "Didn't find the cldap server!\n");
378 if (!ads
->config
.realm
) {
379 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
380 ads
->ldap
.port
= 389;
383 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
384 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
385 d_fprintf(stderr
, "CLDAP query failed!\n");
389 d_printf("Workgroup: %s\n", reply
.domain
);
398 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
400 char **disp_fields
= (char **) data_area
;
402 if (!field
) { /* must be end of record */
403 if (disp_fields
[0]) {
404 if (!strchr_m(disp_fields
[0], '$')) {
406 d_printf("%-21.21s %s\n",
407 disp_fields
[0], disp_fields
[1]);
409 d_printf("%s\n", disp_fields
[0]);
412 SAFE_FREE(disp_fields
[0]);
413 SAFE_FREE(disp_fields
[1]);
416 if (!values
) /* must be new field, indicate string field */
418 if (StrCaseCmp(field
, "sAMAccountName") == 0) {
419 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
421 if (StrCaseCmp(field
, "description") == 0)
422 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
426 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
428 return net_user_usage(c
, argc
, argv
);
431 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
436 LDAPMessage
*res
=NULL
;
440 if (argc
< 1 || c
->display_usage
)
441 return net_ads_user_usage(c
, argc
, argv
);
443 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
447 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
449 if (!ADS_ERR_OK(status
)) {
450 d_fprintf(stderr
, "ads_user_add: %s\n", ads_errstr(status
));
454 if (ads_count_replies(ads
, res
)) {
455 d_fprintf(stderr
, "ads_user_add: User %s already exists\n", argv
[0]);
459 if (c
->opt_container
) {
460 ou_str
= SMB_STRDUP(c
->opt_container
);
462 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
465 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
467 if (!ADS_ERR_OK(status
)) {
468 d_fprintf(stderr
, "Could not add user %s: %s\n", argv
[0],
473 /* if no password is to be set, we're done */
475 d_printf("User %s added\n", argv
[0]);
480 /* try setting the password */
481 asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
);
482 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
483 ads
->auth
.time_offset
);
485 if (ADS_ERR_OK(status
)) {
486 d_printf("User %s added\n", argv
[0]);
491 /* password didn't set, delete account */
492 d_fprintf(stderr
, "Could not add user %s. Error setting password %s\n",
493 argv
[0], ads_errstr(status
));
494 ads_msgfree(ads
, res
);
495 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
496 if (ADS_ERR_OK(status
)) {
497 userdn
= ads_get_dn(ads
, res
);
498 ads_del_dn(ads
, userdn
);
499 ads_memfree(ads
, userdn
);
504 ads_msgfree(ads
, res
);
510 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
515 const char *attrs
[] = {"memberOf", NULL
};
516 char *searchstring
=NULL
;
520 if (argc
< 1 || c
->display_usage
) {
521 return net_ads_user_usage(c
, argc
, argv
);
524 escaped_user
= escape_ldap_string_alloc(argv
[0]);
527 d_fprintf(stderr
, "ads_user_info: failed to escape user %s\n", argv
[0]);
531 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
532 SAFE_FREE(escaped_user
);
536 asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
);
537 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
538 safe_free(searchstring
);
540 if (!ADS_ERR_OK(rc
)) {
541 d_fprintf(stderr
, "ads_search: %s\n", ads_errstr(rc
));
543 SAFE_FREE(escaped_user
);
547 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
548 (LDAPMessage
*)res
, "memberOf");
553 for (i
=0;grouplist
[i
];i
++) {
554 groupname
= ldap_explode_dn(grouplist
[i
], 1);
555 d_printf("%s\n", groupname
[0]);
556 ldap_value_free(groupname
);
558 ldap_value_free(grouplist
);
561 ads_msgfree(ads
, res
);
563 SAFE_FREE(escaped_user
);
567 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
571 LDAPMessage
*res
= NULL
;
575 return net_ads_user_usage(c
, argc
, argv
);
578 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
582 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
583 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
584 d_printf("User %s does not exist.\n", argv
[0]);
585 ads_msgfree(ads
, res
);
589 userdn
= ads_get_dn(ads
, res
);
590 ads_msgfree(ads
, res
);
591 rc
= ads_del_dn(ads
, userdn
);
592 ads_memfree(ads
, userdn
);
593 if (ADS_ERR_OK(rc
)) {
594 d_printf("User %s deleted\n", argv
[0]);
598 d_fprintf(stderr
, "Error deleting user %s: %s\n", argv
[0],
604 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
606 struct functable3 func
[] = {
619 "Display information about an AD user",
620 "net ads user info\n"
621 " Display information about an AD user"
628 "net ads user delete\n"
631 {NULL
, NULL
, 0, NULL
, NULL
}
635 const char *shortattrs
[] = {"sAMAccountName", NULL
};
636 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
637 char *disp_fields
[2] = {NULL
, NULL
};
640 if (c
->display_usage
) {
641 d_printf("Usage:\n");
642 d_printf("net ads user\n"
644 net_display_usage_from_functable(func
);
648 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
652 if (c
->opt_long_list_entries
)
653 d_printf("\nUser name Comment"
654 "\n-----------------------------\n");
656 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
658 "(objectCategory=user)",
659 c
->opt_long_list_entries
? longattrs
:
660 shortattrs
, usergrp_display
,
663 return ADS_ERR_OK(rc
) ? 0 : -1;
666 return net_run_function3(c
, argc
, argv
, "net ads user", func
);
669 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
671 return net_group_usage(c
, argc
, argv
);
674 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
678 LDAPMessage
*res
=NULL
;
682 if (argc
< 1 || c
->display_usage
) {
683 return net_ads_group_usage(c
, argc
, argv
);
686 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
690 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
692 if (!ADS_ERR_OK(status
)) {
693 d_fprintf(stderr
, "ads_group_add: %s\n", ads_errstr(status
));
697 if (ads_count_replies(ads
, res
)) {
698 d_fprintf(stderr
, "ads_group_add: Group %s already exists\n", argv
[0]);
702 if (c
->opt_container
) {
703 ou_str
= SMB_STRDUP(c
->opt_container
);
705 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
708 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
710 if (ADS_ERR_OK(status
)) {
711 d_printf("Group %s added\n", argv
[0]);
714 d_fprintf(stderr
, "Could not add group %s: %s\n", argv
[0],
720 ads_msgfree(ads
, res
);
726 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
730 LDAPMessage
*res
= NULL
;
733 if (argc
< 1 || c
->display_usage
) {
734 return net_ads_group_usage(c
, argc
, argv
);
737 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
741 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
742 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
743 d_printf("Group %s does not exist.\n", argv
[0]);
744 ads_msgfree(ads
, res
);
748 groupdn
= ads_get_dn(ads
, res
);
749 ads_msgfree(ads
, res
);
750 rc
= ads_del_dn(ads
, groupdn
);
751 ads_memfree(ads
, groupdn
);
752 if (ADS_ERR_OK(rc
)) {
753 d_printf("Group %s deleted\n", argv
[0]);
757 d_fprintf(stderr
, "Error deleting group %s: %s\n", argv
[0],
763 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
765 struct functable3 func
[] = {
771 "net ads group add\n"
778 "Delete an AD group",
779 "net ads group delete\n"
780 " Delete an AD group"
782 {NULL
, NULL
, 0, NULL
, NULL
}
786 const char *shortattrs
[] = {"sAMAccountName", NULL
};
787 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
788 char *disp_fields
[2] = {NULL
, NULL
};
791 if (c
->display_usage
) {
792 d_printf("Usage:\n");
793 d_printf("net ads group\n"
794 " List AD groups\n");
795 net_display_usage_from_functable(func
);
799 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
803 if (c
->opt_long_list_entries
)
804 d_printf("\nGroup name Comment"
805 "\n-----------------------------\n");
806 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
808 "(objectCategory=group)",
809 c
->opt_long_list_entries
? longattrs
:
810 shortattrs
, usergrp_display
,
814 return ADS_ERR_OK(rc
) ? 0 : -1;
816 return net_run_function3(c
, argc
, argv
, "net ads group", func
);
819 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
825 if (c
->display_usage
) {
828 " Display machine account details\n");
832 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
836 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
837 if (!ADS_ERR_OK(rc
)) {
838 d_fprintf(stderr
, "ads_find_machine_acct: %s\n", ads_errstr(rc
));
843 if (ads_count_replies(ads
, res
) == 0) {
844 d_fprintf(stderr
, "No machine account for '%s' found\n", global_myname());
854 /*******************************************************************
855 Leave an AD domain. Windows XP disables the machine account.
856 We'll try the same. The old code would do an LDAP delete.
857 That only worked using the machine creds because added the machine
858 with full control to the computer object's ACL.
859 *******************************************************************/
861 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
864 struct libnet_UnjoinCtx
*r
= NULL
;
867 if (c
->display_usage
) {
870 " Leave an AD domain\n");
875 d_fprintf(stderr
, "No realm set, are we joined ?\n");
879 if (!(ctx
= talloc_init("net_ads_leave"))) {
880 d_fprintf(stderr
, "Could not initialise talloc context.\n");
884 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
.dc_name
= c
->opt_host
;
894 r
->in
.domain_name
= lp_realm();
895 r
->in
.admin_account
= c
->opt_user_name
;
896 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
897 r
->in
.modify_config
= lp_config_backend_is_registry();
898 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
899 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
901 werr
= libnet_Unjoin(ctx
, r
);
902 if (!W_ERROR_IS_OK(werr
)) {
903 d_printf("Failed to leave domain: %s\n",
904 r
->out
.error_string
? r
->out
.error_string
:
905 get_friendly_werror_msg(werr
));
909 if (W_ERROR_IS_OK(werr
)) {
910 d_printf("Deleted account for '%s' in realm '%s'\n",
911 r
->in
.machine_name
, r
->out
.dns_domain_name
);
915 /* We couldn't delete it - see if the disable succeeded. */
916 if (r
->out
.disabled_machine_account
) {
917 d_printf("Disabled account for '%s' in realm '%s'\n",
918 r
->in
.machine_name
, r
->out
.dns_domain_name
);
923 d_fprintf(stderr
, "Failed to disable machine account for '%s' in realm '%s'\n",
924 r
->in
.machine_name
, r
->out
.dns_domain_name
);
930 if (W_ERROR_IS_OK(werr
)) {
937 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
939 ADS_STRUCT
*ads
= NULL
;
942 if (!secrets_init()) {
943 DEBUG(1,("Failed to initialise secrets database\n"));
944 return NT_STATUS_ACCESS_DENIED
;
947 net_use_krb_machine_account(c
);
949 status
= ads_startup(c
, true, &ads
);
950 if (!ADS_ERR_OK(status
)) {
951 return ads_ntstatus(status
);
959 check that an existing join is OK
961 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
964 use_in_memory_ccache();
966 if (c
->display_usage
) {
969 " Test if the existing join is ok\n");
973 /* Display success or failure */
974 status
= net_ads_join_ok(c
);
975 if (!NT_STATUS_IS_OK(status
)) {
976 fprintf(stderr
,"Join to domain is not valid: %s\n",
977 get_friendly_nt_error_msg(status
));
981 printf("Join is OK\n");
985 /*******************************************************************
986 Simple configu checks before beginning the join
987 ********************************************************************/
989 static WERROR
check_ads_config( void )
991 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
992 d_printf("Host is not configured as a member server.\n");
993 return WERR_INVALID_DOMAIN_ROLE
;
996 if (strlen(global_myname()) > 15) {
997 d_printf("Our netbios name can be at most 15 chars long, "
998 "\"%s\" is %u chars long\n", global_myname(),
999 (unsigned int)strlen(global_myname()));
1000 return WERR_INVALID_COMPUTER_NAME
;
1003 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1004 d_fprintf(stderr
, "realm must be set in in %s for ADS "
1005 "join to succeed.\n", get_dyn_CONFIGFILE());
1006 return WERR_INVALID_PARAM
;
1012 /*******************************************************************
1013 Send a DNS update request
1014 *******************************************************************/
1016 #if defined(WITH_DNS_UPDATES)
1018 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
1019 const char *pszDomainName
, const char *pszHostName
,
1020 const struct sockaddr_storage
*sslist
,
1023 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1024 const char *machine_name
,
1025 const struct sockaddr_storage
*addrs
,
1028 struct dns_rr_ns
*nameservers
= NULL
;
1030 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1033 const char *dnsdomain
= NULL
;
1034 char *root_domain
= NULL
;
1036 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1037 d_printf("No DNS domain configured for %s. "
1038 "Unable to perform DNS Update.\n", machine_name
);
1039 status
= NT_STATUS_INVALID_PARAMETER
;
1044 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
1045 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1046 /* Child domains often do not have NS records. Look
1047 for the NS record for the forest root domain
1048 (rootDomainNamingContext in therootDSE) */
1050 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1051 LDAPMessage
*msg
= NULL
;
1053 ADS_STATUS ads_status
;
1055 if ( !ads
->ldap
.ld
) {
1056 ads_status
= ads_connect( ads
);
1057 if ( !ADS_ERR_OK(ads_status
) ) {
1058 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1063 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1064 "(objectclass=*)", rootname_attrs
, &msg
);
1065 if (!ADS_ERR_OK(ads_status
)) {
1069 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1071 ads_msgfree( ads
, msg
);
1075 root_domain
= ads_build_domain( root_dn
);
1078 ads_msgfree( ads
, msg
);
1080 /* try again for NS servers */
1082 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1084 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1085 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1086 "realm\n", ads
->config
.realm
));
1090 dnsdomain
= root_domain
;
1094 /* Now perform the dns update - we'll try non-secure and if we fail,
1095 we'll follow it up with a secure update */
1097 fstrcpy( dns_server
, nameservers
[0].hostname
);
1099 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1100 if (!ERR_DNS_IS_OK(dns_err
)) {
1101 status
= NT_STATUS_UNSUCCESSFUL
;
1106 SAFE_FREE( root_domain
);
1111 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
)
1114 struct sockaddr_storage
*iplist
= NULL
;
1115 fstring machine_name
;
1118 name_to_fqdn( machine_name
, global_myname() );
1119 strlower_m( machine_name
);
1121 /* Get our ip address (not the 127.0.0.x address but a real ip
1124 num_addrs
= get_my_ip_address( &iplist
);
1125 if ( num_addrs
<= 0 ) {
1126 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1128 return NT_STATUS_INVALID_PARAMETER
;
1131 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1133 SAFE_FREE( iplist
);
1139 /*******************************************************************
1140 ********************************************************************/
1142 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1144 d_printf("net ads join [options]\n");
1145 d_printf("Valid options:\n");
1146 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1147 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1148 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1149 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1150 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1151 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1152 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1153 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1154 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1155 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1156 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1157 d_printf(" the two other attributes.\n");
1162 /*******************************************************************
1163 ********************************************************************/
1165 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1167 TALLOC_CTX
*ctx
= NULL
;
1168 struct libnet_JoinCtx
*r
= NULL
;
1169 const char *domain
= lp_realm();
1170 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1171 bool createupn
= false;
1172 const char *machineupn
= NULL
;
1173 const char *create_in_ou
= NULL
;
1175 const char *os_name
= NULL
;
1176 const char *os_version
= NULL
;
1177 bool modify_config
= lp_config_backend_is_registry();
1179 if (c
->display_usage
)
1180 return net_ads_join_usage(c
, argc
, argv
);
1182 if (!modify_config
) {
1184 werr
= check_ads_config();
1185 if (!W_ERROR_IS_OK(werr
)) {
1186 d_fprintf(stderr
, "Invalid configuration. Exiting....\n");
1191 if (!(ctx
= talloc_init("net_ads_join"))) {
1192 d_fprintf(stderr
, "Could not initialise talloc context.\n");
1197 use_in_memory_ccache();
1199 werr
= libnet_init_JoinCtx(ctx
, &r
);
1200 if (!W_ERROR_IS_OK(werr
)) {
1204 /* process additional command line args */
1206 for ( i
=0; i
<argc
; i
++ ) {
1207 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1209 machineupn
= get_string_param(argv
[i
]);
1211 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1212 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1213 d_fprintf(stderr
, "Please supply a valid OU path.\n");
1214 werr
= WERR_INVALID_PARAM
;
1218 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1219 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1220 d_fprintf(stderr
, "Please supply a operating system name.\n");
1221 werr
= WERR_INVALID_PARAM
;
1225 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1226 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1227 d_fprintf(stderr
, "Please supply a valid operating system version.\n");
1228 werr
= WERR_INVALID_PARAM
;
1238 d_fprintf(stderr
, "Please supply a valid domain name\n");
1239 werr
= WERR_INVALID_PARAM
;
1243 /* Do the domain join here */
1245 r
->in
.domain_name
= domain
;
1246 r
->in
.create_upn
= createupn
;
1247 r
->in
.upn
= machineupn
;
1248 r
->in
.account_ou
= create_in_ou
;
1249 r
->in
.os_name
= os_name
;
1250 r
->in
.os_version
= os_version
;
1251 r
->in
.dc_name
= c
->opt_host
;
1252 r
->in
.admin_account
= c
->opt_user_name
;
1253 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1255 r
->in
.modify_config
= modify_config
;
1256 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1257 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1258 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1260 werr
= libnet_Join(ctx
, r
);
1261 if (!W_ERROR_IS_OK(werr
)) {
1265 /* Check the short name of the domain */
1267 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1268 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1269 d_printf("domain name obtained from the server.\n");
1270 d_printf("Using the name [%s] from the server.\n", r
->out
.netbios_domain_name
);
1271 d_printf("You should set \"workgroup = %s\" in %s.\n",
1272 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1275 d_printf("Using short domain name -- %s\n", r
->out
.netbios_domain_name
);
1277 if (r
->out
.dns_domain_name
) {
1278 d_printf("Joined '%s' to realm '%s'\n", r
->in
.machine_name
,
1279 r
->out
.dns_domain_name
);
1281 d_printf("Joined '%s' to domain '%s'\n", r
->in
.machine_name
,
1282 r
->out
.netbios_domain_name
);
1285 #if defined(WITH_DNS_UPDATES)
1286 if (r
->out
.domain_is_ad
) {
1287 /* We enter this block with user creds */
1288 ADS_STRUCT
*ads_dns
= NULL
;
1290 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1291 /* kinit with the machine password */
1293 use_in_memory_ccache();
1294 asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname() );
1295 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1296 r
->out
.netbios_domain_name
, NULL
, NULL
);
1297 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1298 strupper_m(ads_dns
->auth
.realm
);
1299 ads_kinit_password( ads_dns
);
1302 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns( ctx
, ads_dns
)) ) {
1303 d_fprintf( stderr
, "DNS update failed!\n" );
1306 /* exit from this block using machine creds */
1307 ads_destroy(&ads_dns
);
1316 /* issue an overall failure message at the end. */
1317 d_printf("Failed to join domain: %s\n",
1318 r
&& r
->out
.error_string
? r
->out
.error_string
:
1319 get_friendly_werror_msg(werr
));
1325 /*******************************************************************
1326 ********************************************************************/
1328 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1330 #if defined(WITH_DNS_UPDATES)
1336 talloc_enable_leak_report();
1339 if (argc
> 0 || c
->display_usage
) {
1341 "net ads dns register\n"
1342 " Register hostname with DNS\n");
1346 if (!(ctx
= talloc_init("net_ads_dns"))) {
1347 d_fprintf(stderr
, "Could not initialise talloc context\n");
1351 status
= ads_startup(c
, true, &ads
);
1352 if ( !ADS_ERR_OK(status
) ) {
1353 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1358 if ( !NT_STATUS_IS_OK(net_update_dns(ctx
, ads
)) ) {
1359 d_fprintf( stderr
, "DNS update failed!\n" );
1360 ads_destroy( &ads
);
1365 d_fprintf( stderr
, "Successfully registered hostname with DNS\n" );
1372 d_fprintf(stderr
, "DNS update support not enabled at compile time!\n");
1377 #if defined(WITH_DNS_UPDATES)
1378 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1381 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1383 #if defined(WITH_DNS_UPDATES)
1387 talloc_enable_leak_report();
1390 if (argc
!= 2 || c
->display_usage
) {
1392 "net ads dns gethostbyname <server> <name>\n"
1393 " Look up hostname from the AD\n"
1394 " server\tName server to use\n"
1395 " name\tName to look up\n");
1399 err
= do_gethostbyname(argv
[0], argv
[1]);
1401 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err
));
1406 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1408 struct functable3 func
[] = {
1411 net_ads_dns_register
,
1413 "Add host dns entry to AD",
1414 "net ads dns register\n"
1415 " Add host dns entry to AD"
1419 net_ads_dns_gethostbyname
,
1422 "net ads dns gethostbyname\n"
1425 {NULL
, NULL
, 0, NULL
, NULL
}
1428 return net_run_function3(c
, argc
, argv
, "net ads dns", func
);
1431 /*******************************************************************
1432 ********************************************************************/
1434 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1437 "\nnet ads printer search <printer>"
1438 "\n\tsearch for a printer in the directory\n"
1439 "\nnet ads printer info <printer> <server>"
1440 "\n\tlookup info in directory for printer on server"
1441 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1442 "\nnet ads printer publish <printername>"
1443 "\n\tpublish printer in directory"
1444 "\n\t(note: printer name is required)\n"
1445 "\nnet ads printer remove <printername>"
1446 "\n\tremove printer from directory"
1447 "\n\t(note: printer name is required)\n");
1451 /*******************************************************************
1452 ********************************************************************/
1454 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1458 LDAPMessage
*res
= NULL
;
1460 if (c
->display_usage
) {
1462 "net ads printer search\n"
1463 " List printers in the AD\n");
1467 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1471 rc
= ads_find_printers(ads
, &res
);
1473 if (!ADS_ERR_OK(rc
)) {
1474 d_fprintf(stderr
, "ads_find_printer: %s\n", ads_errstr(rc
));
1475 ads_msgfree(ads
, res
);
1480 if (ads_count_replies(ads
, res
) == 0) {
1481 d_fprintf(stderr
, "No results found\n");
1482 ads_msgfree(ads
, res
);
1488 ads_msgfree(ads
, res
);
1493 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1497 const char *servername
, *printername
;
1498 LDAPMessage
*res
= NULL
;
1500 if (c
->display_usage
) {
1502 "net ads printer info [printername [servername]]\n"
1503 " Display printer info from AD\n"
1504 " printername\tPrinter name or wildcard\n"
1505 " servername\tName of the print server\n");
1509 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1514 printername
= argv
[0];
1520 servername
= argv
[1];
1522 servername
= global_myname();
1525 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1527 if (!ADS_ERR_OK(rc
)) {
1528 d_fprintf(stderr
, "Server '%s' not found: %s\n",
1529 servername
, ads_errstr(rc
));
1530 ads_msgfree(ads
, res
);
1535 if (ads_count_replies(ads
, res
) == 0) {
1536 d_fprintf(stderr
, "Printer '%s' not found\n", printername
);
1537 ads_msgfree(ads
, res
);
1543 ads_msgfree(ads
, res
);
1549 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1553 const char *servername
, *printername
;
1554 struct cli_state
*cli
;
1555 struct rpc_pipe_client
*pipe_hnd
;
1556 struct sockaddr_storage server_ss
;
1558 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1559 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1560 char *prt_dn
, *srv_dn
, **srv_cn
;
1561 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1562 LDAPMessage
*res
= NULL
;
1564 if (argc
< 1 || c
->display_usage
) {
1566 "net ads printer publish <printername> [servername]\n"
1567 " Publish printer in AD\n"
1568 " printername\tName of the printer\n"
1569 " servername\tName of the print server\n");
1570 talloc_destroy(mem_ctx
);
1574 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1575 talloc_destroy(mem_ctx
);
1579 printername
= argv
[0];
1582 servername
= argv
[1];
1584 servername
= global_myname();
1587 /* Get printer data from SPOOLSS */
1589 resolve_name(servername
, &server_ss
, 0x20);
1591 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1594 c
->opt_user_name
, c
->opt_workgroup
,
1595 c
->opt_password
? c
->opt_password
: "",
1596 CLI_FULL_CONNECTION_USE_KERBEROS
,
1599 if (NT_STATUS_IS_ERR(nt_status
)) {
1600 d_fprintf(stderr
, "Unable to open a connnection to %s to obtain data "
1601 "for %s\n", servername
, printername
);
1603 talloc_destroy(mem_ctx
);
1607 /* Publish on AD server */
1609 ads_find_machine_acct(ads
, &res
, servername
);
1611 if (ads_count_replies(ads
, res
) == 0) {
1612 d_fprintf(stderr
, "Could not find machine account for server %s\n",
1615 talloc_destroy(mem_ctx
);
1619 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1620 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1622 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1623 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1624 if (!srv_cn_escaped
|| !printername_escaped
) {
1625 SAFE_FREE(srv_cn_escaped
);
1626 SAFE_FREE(printername_escaped
);
1627 d_fprintf(stderr
, "Internal error, out of memory!");
1629 talloc_destroy(mem_ctx
);
1633 asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
);
1635 SAFE_FREE(srv_cn_escaped
);
1636 SAFE_FREE(printername_escaped
);
1638 pipe_hnd
= cli_rpc_pipe_open_noauth(cli
, PI_SPOOLSS
, &nt_status
);
1640 d_fprintf(stderr
, "Unable to open a connnection to the spoolss pipe on %s\n",
1644 talloc_destroy(mem_ctx
);
1648 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1652 talloc_destroy(mem_ctx
);
1656 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1657 if (!ADS_ERR_OK(rc
)) {
1658 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1661 talloc_destroy(mem_ctx
);
1665 d_printf("published printer\n");
1668 talloc_destroy(mem_ctx
);
1673 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1677 const char *servername
;
1679 LDAPMessage
*res
= NULL
;
1681 if (argc
< 1 || c
->display_usage
) {
1683 "net ads printer remove <printername> [servername]\n"
1684 " Remove a printer from the AD\n"
1685 " printername\tName of the printer\n"
1686 " servername\tName of the print server\n");
1690 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1695 servername
= argv
[1];
1697 servername
= global_myname();
1700 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1702 if (!ADS_ERR_OK(rc
)) {
1703 d_fprintf(stderr
, "ads_find_printer_on_server: %s\n", ads_errstr(rc
));
1704 ads_msgfree(ads
, res
);
1709 if (ads_count_replies(ads
, res
) == 0) {
1710 d_fprintf(stderr
, "Printer '%s' not found\n", argv
[1]);
1711 ads_msgfree(ads
, res
);
1716 prt_dn
= ads_get_dn(ads
, res
);
1717 ads_msgfree(ads
, res
);
1718 rc
= ads_del_dn(ads
, prt_dn
);
1719 ads_memfree(ads
, prt_dn
);
1721 if (!ADS_ERR_OK(rc
)) {
1722 d_fprintf(stderr
, "ads_del_dn: %s\n", ads_errstr(rc
));
1731 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
1733 struct functable3 func
[] = {
1736 net_ads_printer_search
,
1738 "Search for a printer",
1739 "net ads printer search\n"
1740 " Search for a printer"
1744 net_ads_printer_info
,
1746 "Display printer information",
1747 "net ads printer info\n"
1748 " Display printer information"
1752 net_ads_printer_publish
,
1754 "Publish a printer",
1755 "net ads printer publish\n"
1756 " Publish a printer"
1760 net_ads_printer_remove
,
1763 "net ads printer remove\n"
1766 {NULL
, NULL
, 0, NULL
, NULL
}
1769 return net_run_function3(c
, argc
, argv
, "net ads printer", func
);
1773 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
1776 const char *auth_principal
= c
->opt_user_name
;
1777 const char *auth_password
= c
->opt_password
;
1779 char *new_password
= NULL
;
1784 if (c
->display_usage
) {
1786 "net ads password <username>\n"
1787 " Change password for user\n"
1788 " username\tName of user to change password for\n");
1792 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
1793 d_fprintf(stderr
, "You must supply an administrator username/password\n");
1798 d_fprintf(stderr
, "ERROR: You must say which username to change password for\n");
1803 if (!strchr_m(user
, '@')) {
1804 asprintf(&chr
, "%s@%s", argv
[0], lp_realm());
1808 use_in_memory_ccache();
1809 chr
= strchr_m(auth_principal
, '@');
1816 /* use the realm so we can eventually change passwords for users
1817 in realms other than default */
1818 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
1822 /* we don't actually need a full connect, but it's the easy way to
1823 fill in the KDC's addresss */
1826 if (!ads
->config
.realm
) {
1827 d_fprintf(stderr
, "Didn't find the kerberos server!\n");
1832 new_password
= (char *)argv
[1];
1834 asprintf(&prompt
, "Enter new password for %s:", user
);
1835 new_password
= getpass(prompt
);
1839 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
1840 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
1841 if (!ADS_ERR_OK(ret
)) {
1842 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1847 d_printf("Password change for %s completed.\n", user
);
1853 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
1856 char *host_principal
;
1860 if (c
->display_usage
) {
1862 "net ads changetrustpw\n"
1863 " Change the machine account's trust password\n");
1867 if (!secrets_init()) {
1868 DEBUG(1,("Failed to initialise secrets database\n"));
1872 net_use_krb_machine_account(c
);
1874 use_in_memory_ccache();
1876 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1880 fstrcpy(my_name
, global_myname());
1881 strlower_m(my_name
);
1882 asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
);
1883 d_printf("Changing password for principal: %s\n", host_principal
);
1885 ret
= ads_change_trust_account_password(ads
, host_principal
);
1887 if (!ADS_ERR_OK(ret
)) {
1888 d_fprintf(stderr
, "Password change failed: %s\n", ads_errstr(ret
));
1890 SAFE_FREE(host_principal
);
1894 d_printf("Password change for principal %s succeeded.\n", host_principal
);
1896 if (lp_use_kerberos_keytab()) {
1897 d_printf("Attempting to update system keytab with new password.\n");
1898 if (ads_keytab_create_default(ads
)) {
1899 d_printf("Failed to update system keytab.\n");
1904 SAFE_FREE(host_principal
);
1910 help for net ads search
1912 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
1915 "\nnet ads search <expression> <attributes...>\n"
1916 "\nperform a raw LDAP search on a ADS server and dump the results\n"
1917 "The expression is a standard LDAP search expression, and the\n"
1918 "attributes are a list of LDAP fields to show in the results\n\n"
1919 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1921 net_common_flags_usage(c
, argc
, argv
);
1927 general ADS search function. Useful in diagnosing problems in ADS
1929 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
1933 const char *ldap_exp
;
1935 LDAPMessage
*res
= NULL
;
1937 if (argc
< 1 || c
->display_usage
) {
1938 return net_ads_search_usage(c
, argc
, argv
);
1941 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1948 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
1950 ldap_exp
, attrs
, &res
);
1951 if (!ADS_ERR_OK(rc
)) {
1952 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
1957 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
1959 /* dump the results */
1962 ads_msgfree(ads
, res
);
1970 help for net ads search
1972 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
1975 "\nnet ads dn <dn> <attributes...>\n"
1976 "\nperform a raw LDAP search on a ADS server and dump the results\n"
1977 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
1978 "to show in the results\n\n"
1979 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1980 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1982 net_common_flags_usage(c
, argc
, argv
);
1988 general ADS search function. Useful in diagnosing problems in ADS
1990 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
1996 LDAPMessage
*res
= NULL
;
1998 if (argc
< 1 || c
->display_usage
) {
1999 return net_ads_dn_usage(c
, argc
, argv
);
2002 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2009 rc
= ads_do_search_all(ads
, dn
,
2011 "(objectclass=*)", attrs
, &res
);
2012 if (!ADS_ERR_OK(rc
)) {
2013 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
2018 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2020 /* dump the results */
2023 ads_msgfree(ads
, res
);
2030 help for net ads sid search
2032 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2035 "\nnet ads sid <sid> <attributes...>\n"
2036 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2037 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2038 "to show in the results\n\n"
2039 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2041 net_common_flags_usage(c
, argc
, argv
);
2047 general ADS search function. Useful in diagnosing problems in ADS
2049 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2053 const char *sid_string
;
2055 LDAPMessage
*res
= NULL
;
2058 if (argc
< 1 || c
->display_usage
) {
2059 return net_ads_sid_usage(c
, argc
, argv
);
2062 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2066 sid_string
= argv
[0];
2069 if (!string_to_sid(&sid
, sid_string
)) {
2070 d_fprintf(stderr
, "could not convert sid\n");
2075 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2076 if (!ADS_ERR_OK(rc
)) {
2077 d_fprintf(stderr
, "search failed: %s\n", ads_errstr(rc
));
2082 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2084 /* dump the results */
2087 ads_msgfree(ads
, res
);
2093 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2098 if (c
->display_usage
) {
2100 "net ads keytab flush\n"
2101 " Delete the whole keytab\n");
2105 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2108 ret
= ads_keytab_flush(ads
);
2113 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2119 if (c
->display_usage
) {
2121 "net ads keytab add <principal> [principal ...]\n"
2122 " Add principals to local keytab\n"
2123 " principal\tKerberos principal to add to "
2128 d_printf("Processing principals to add...\n");
2129 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2132 for (i
= 0; i
< argc
; i
++) {
2133 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2139 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2144 if (c
->display_usage
) {
2146 "net ads keytab create\n"
2147 " Create new default keytab\n");
2151 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2154 ret
= ads_keytab_create_default(ads
);
2159 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2161 const char *keytab
= NULL
;
2163 if (c
->display_usage
) {
2165 "net ads keytab list [keytab]\n"
2166 " List a local keytab\n"
2167 " keytab\tKeytab to list\n");
2175 return ads_keytab_list(keytab
);
2179 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2181 struct functable3 func
[] = {
2186 "Add a service principal",
2187 "net ads keytab add\n"
2188 " Add a service principal"
2192 net_ads_keytab_create
,
2194 "Create a fresh keytab",
2195 "net ads keytab create\n"
2196 " Create a fresh keytab"
2200 net_ads_keytab_flush
,
2202 "Remove all keytab entries",
2203 "net ads keytab flush\n"
2204 " Remove all keytab entries"
2208 net_ads_keytab_list
,
2211 "net ads keytab list\n"
2214 {NULL
, NULL
, 0, NULL
, NULL
}
2217 if (!lp_use_kerberos_keytab()) {
2218 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2219 use keytab functions.\n");
2222 return net_run_function3(c
, argc
, argv
, "net ads keytab", func
);
2225 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2229 if (c
->display_usage
) {
2231 "net ads kerberos renew\n"
2232 " Renew TGT from existing credential cache\n");
2236 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2238 d_printf("failed to renew kerberos ticket: %s\n",
2239 error_message(ret
));
2244 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2246 struct PAC_DATA
*pac
= NULL
;
2247 struct PAC_LOGON_INFO
*info
= NULL
;
2248 TALLOC_CTX
*mem_ctx
= NULL
;
2252 if (c
->display_usage
) {
2254 "net ads kerberos pac\n"
2255 " Dump the Kerberos PAC\n");
2259 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2264 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2266 status
= kerberos_return_pac(mem_ctx
,
2275 2592000, /* one month */
2277 if (!NT_STATUS_IS_OK(status
)) {
2278 d_printf("failed to query kerberos PAC: %s\n",
2283 info
= get_logon_info_from_pac(pac
);
2286 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2287 d_printf("The Pac: %s\n", s
);
2292 TALLOC_FREE(mem_ctx
);
2296 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2298 TALLOC_CTX
*mem_ctx
= NULL
;
2302 if (c
->display_usage
) {
2304 "net ads kerberos kinit\n"
2305 " Get Ticket Granting Ticket (TGT) for the user\n");
2309 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2314 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2316 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2324 2592000, /* one month */
2327 d_printf("failed to kinit password: %s\n",
2334 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2336 struct functable3 func
[] = {
2339 net_ads_kerberos_kinit
,
2341 "Retrieve Ticket Granting Ticket (TGT)",
2342 "net ads kerberos kinit\n"
2343 " Receive Ticket Granting Ticket (TGT)"
2347 net_ads_kerberos_renew
,
2349 "Renew Ticket Granting Ticket from credential cache"
2350 "net ads kerberos renew\n"
2351 " Renew Ticket Granting Ticket from credential cache"
2355 net_ads_kerberos_pac
,
2357 "Dump Kerberos PAC",
2358 "net ads kerberos pac\n"
2359 " Dump Kerberos PAC"
2361 {NULL
, NULL
, 0, NULL
, NULL
}
2364 return net_run_function3(c
, argc
, argv
, "net ads kerberos", func
);
2367 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2369 struct functable3 func
[] = {
2374 "Display details on remote ADS server",
2376 " Display details on remote ADS server"
2382 "Join the local machine to ADS realm",
2384 " Join the local machine to ADS realm"
2390 "Validate machine account",
2391 "net ads testjoin\n"
2392 " Validate machine account"
2398 "Remove the local machine from ADS",
2400 " Remove the local machine from ADS"
2406 "Display machine account details",
2408 " Display machine account details"
2414 "List/modify users",
2416 " List/modify users"
2422 "List/modify groups",
2424 " List/modify groups"
2430 "Issue dynamic DNS update",
2432 " Issue dynamic DNS update"
2438 "Change user passwords",
2439 "net ads password\n"
2440 " Change user passwords"
2444 net_ads_changetrustpw
,
2446 "Change trust account password",
2447 "net ads changetrustpw\n"
2448 " Change trust account password"
2454 "List/modify printer entries",
2456 " List/modify printer entries"
2462 "Issue LDAP search using filter",
2464 " Issue LDAP search using filter"
2470 "Issue LDAP search by DN",
2472 " Issue LDAP search by DN"
2478 "Issue LDAP search by SID",
2480 " Issue LDAP search by SID"
2486 "Display workgroup name",
2487 "net ads workgroup\n"
2488 " Display the workgroup name"
2494 "Perfom CLDAP query on DC",
2496 " Find the ADS DC using CLDAP lookups"
2502 "Manage local keytab file",
2504 " Manage local keytab file"
2510 "Manage group policy objects",
2512 " Manage group policy objects"
2518 "Manage kerberos keytab",
2519 "net ads kerberos\n"
2520 " Manage kerberos keytab"
2522 {NULL
, NULL
, 0, NULL
, NULL
}
2525 return net_run_function3(c
, argc
, argv
, "net ads", func
);
2530 static int net_ads_noads(void)
2532 d_fprintf(stderr
, "ADS support not compiled in\n");
2536 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2538 return net_ads_noads();
2541 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2543 return net_ads_noads();
2546 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2548 return net_ads_noads();
2551 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2553 return net_ads_noads();
2556 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2558 return net_ads_noads();
2561 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2563 return net_ads_noads();
2566 /* this one shouldn't display a message */
2567 int net_ads_check(struct net_context
*c
)
2572 int net_ads_check_our_domain(struct net_context
*c
)
2577 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2579 return net_ads_usage(c
, argc
, argv
);
2582 #endif /* WITH_ADS */