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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "utils/net.h"
29 int net_ads_usage(int argc, const char **argv)
31 d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
32 d_printf(" Join the local machine to a ADS realm\n");
34 d_printf(" Remove the local machine from a ADS realm\n");
35 d_printf("testjoin\n");
36 d_printf(" Validates the machine account in the domain\n");
38 d_printf(" List, add, or delete users in the realm\n");
40 d_printf(" List, add, or delete groups in the realm\n");
42 d_printf(" Displays details regarding a specific AD server\n");
44 d_printf(" Display details regarding the machine's account in AD\n");
46 d_printf(" Performs CLDAP query of AD domain controllers\n");
47 d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
48 d_printf(" Change a user's password using an admin account\n");
49 d_printf(" (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
50 d_printf("changetrustpw\n");
51 d_printf(" Change the trust account password of this machine in the AD tree\n");
52 d_printf("printer [info | publish | remove] <printername> <servername>\n");
53 d_printf(" Lookup, add, or remove directory entry for a printer\n");
54 d_printf("{search,dn,sid}\n");
55 d_printf(" Issue LDAP search queries using a general filter, by DN, or by SID\n");
57 d_printf(" Manage a local keytab file based on the machine account in AD\n");
59 d_printf(" Issue a dynamic DNS update request the server's hostname\n");
60 d_printf(" (using the machine credentials)\n");
65 /* when we do not have sufficient input parameters to contact a remote domain
66 * we always fall back to our own realm - Guenther*/
68 static const char *assume_own_realm(void)
70 if (!opt_host && strequal(lp_workgroup(), opt_target_workgroup)) {
78 do a cldap netlogon query
80 static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
82 struct cldap_netlogon_reply reply;
84 if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap_ip), ads->server.realm, &reply ) ) {
85 d_fprintf(stderr, "CLDAP query failed!\n");
89 d_printf("Information for Domain Controller: %s\n\n",
90 inet_ntoa(ads->ldap_ip));
92 d_printf("Response Type: ");
94 case SAMLOGON_AD_UNK_R:
95 d_printf("SAMLOGON\n");
98 d_printf("SAMLOGON_USER\n");
101 d_printf("0x%x\n", reply.type);
104 d_printf("GUID: %s\n",
105 smb_uuid_string_static(smb_uuid_unpack_static(reply.guid)));
108 "\tIs a GC of the forest: %s\n"
109 "\tIs an LDAP server: %s\n"
110 "\tSupports DS: %s\n"
111 "\tIs running a KDC: %s\n"
112 "\tIs running time services: %s\n"
113 "\tIs the closest DC: %s\n"
114 "\tIs writable: %s\n"
115 "\tHas a hardware clock: %s\n"
116 "\tIs a non-domain NC serviced by LDAP server: %s\n",
117 (reply.flags & ADS_PDC) ? "yes" : "no",
118 (reply.flags & ADS_GC) ? "yes" : "no",
119 (reply.flags & ADS_LDAP) ? "yes" : "no",
120 (reply.flags & ADS_DS) ? "yes" : "no",
121 (reply.flags & ADS_KDC) ? "yes" : "no",
122 (reply.flags & ADS_TIMESERV) ? "yes" : "no",
123 (reply.flags & ADS_CLOSEST) ? "yes" : "no",
124 (reply.flags & ADS_WRITABLE) ? "yes" : "no",
125 (reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
126 (reply.flags & ADS_NDNC) ? "yes" : "no");
128 printf("Forest:\t\t\t%s\n", reply.forest);
129 printf("Domain:\t\t\t%s\n", reply.domain);
130 printf("Domain Controller:\t%s\n", reply.hostname);
132 printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
133 printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
135 if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
136 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
138 printf("Server Site Name :\t\t%s\n", reply.server_site_name);
139 printf("Client Site Name :\t\t%s\n", reply.client_site_name);
141 d_printf("NT Version: %d\n", reply.version);
142 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
143 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
150 this implements the CLDAP based netlogon lookup requests
151 for finding the domain controller of a ADS domain
153 static int net_ads_lookup(int argc, const char **argv)
157 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
158 d_fprintf(stderr, "Didn't find the cldap server!\n");
162 if (!ads->config.realm) {
163 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
164 ads->ldap_port = 389;
167 return net_ads_cldap_netlogon(ads);
172 static int net_ads_info(int argc, const char **argv)
176 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
177 d_fprintf(stderr, "Didn't find the ldap server!\n");
181 if (!ads || !ads->config.realm) {
182 d_fprintf(stderr, "Didn't find the ldap server!\n");
186 /* Try to set the server's current time since we didn't do a full
187 TCP LDAP session initially */
189 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
190 d_fprintf( stderr, "Failed to get server's current time!\n");
193 d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
194 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
195 d_printf("Realm: %s\n", ads->config.realm);
196 d_printf("Bind Path: %s\n", ads->config.bind_path);
197 d_printf("LDAP port: %d\n", ads->ldap_port);
198 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
200 d_printf("KDC server: %s\n", ads->auth.kdc_server );
201 d_printf("Server time offset: %d\n", ads->auth.time_offset );
206 static void use_in_memory_ccache(void) {
207 /* Use in-memory credentials cache so we do not interfere with
208 * existing credentials */
209 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
212 static ADS_STATUS ads_startup_int(BOOL only_own_domain, uint32 auth_flags, ADS_STRUCT **ads_ret)
214 ADS_STRUCT *ads = NULL;
216 BOOL need_password = False;
217 BOOL second_time = False;
219 const char *realm = NULL;
220 BOOL tried_closest_dc = False;
221 BOOL closest_dc = False;
222 BOOL site_matches = False;
224 /* lp_realm() should be handled by a command line param,
225 However, the join requires that realm be set in smb.conf
226 and compares our realm with the remote server's so this is
227 ok until someone needs more flexibility */
232 if (only_own_domain) {
235 realm = assume_own_realm();
238 ads = ads_init(realm, opt_target_workgroup, opt_host);
240 if (!opt_user_name) {
241 opt_user_name = "administrator";
244 if (opt_user_specified) {
245 need_password = True;
249 if (!opt_password && need_password && !opt_machine_pass) {
251 asprintf(&prompt,"%s's password: ", opt_user_name);
254 return ADS_ERROR(LDAP_NO_MEMORY);
256 opt_password = getpass(prompt);
261 use_in_memory_ccache();
262 SAFE_FREE(ads->auth.password);
263 ads->auth.password = smb_xstrdup(opt_password);
266 ads->auth.flags |= auth_flags;
267 SAFE_FREE(ads->auth.user_name);
268 ads->auth.user_name = smb_xstrdup(opt_user_name);
271 * If the username is of the form "name@realm",
272 * extract the realm and convert to upper case.
273 * This is only used to establish the connection.
275 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
277 SAFE_FREE(ads->auth.realm);
278 ads->auth.realm = smb_xstrdup(cp);
279 strupper_m(ads->auth.realm);
282 status = ads_connect(ads);
284 if (!ADS_ERR_OK(status)) {
286 if (NT_STATUS_EQUAL(ads_ntstatus(status),
287 NT_STATUS_NO_LOGON_SERVERS)) {
288 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
293 if (!need_password && !second_time) {
294 need_password = True;
303 /* when contacting our own domain, make sure we use the closest DC.
304 * This is done by reconnecting to ADS because only the first call to
305 * ads_connect will give us our own sitename */
307 closest_dc = (ads->config.flags & ADS_CLOSEST);
308 site_matches = ads_sitename_match(ads);
310 DEBUG(10,("ads_startup_int: DC %s closest DC\n", closest_dc ? "is":"is *NOT*"));
311 DEBUG(10,("ads_startup_int: sitenames %s match\n", site_matches ? "do":"do *NOT*"));
313 if ((only_own_domain || !opt_host) && !tried_closest_dc) {
315 tried_closest_dc = True; /* avoid loop */
317 if (!closest_dc || !site_matches) {
319 namecache_delete(ads->server.realm, 0x1C);
320 namecache_delete(ads->server.workgroup, 0x1C);
333 ADS_STATUS ads_startup(BOOL only_own_domain, ADS_STRUCT **ads)
335 return ads_startup_int(only_own_domain, 0, ads);
338 ADS_STATUS ads_startup_nobind(BOOL only_own_domain, ADS_STRUCT **ads)
340 return ads_startup_int(only_own_domain, ADS_AUTH_NO_BIND, ads);
344 Check to see if connection can be made via ads.
345 ads_startup() stores the password in opt_password if it needs to so
346 that rpc or rap can use it without re-prompting.
348 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
353 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
357 ads->auth.flags |= ADS_AUTH_NO_BIND;
359 status = ads_connect(ads);
360 if ( !ADS_ERR_OK(status) ) {
368 int net_ads_check_our_domain(void)
370 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
373 int net_ads_check(void)
375 return net_ads_check_int(NULL, opt_workgroup, opt_host);
378 determine the netbios workgroup name for a domain
380 static int net_ads_workgroup(int argc, const char **argv)
383 struct cldap_netlogon_reply reply;
385 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
386 d_fprintf(stderr, "Didn't find the cldap server!\n");
390 if (!ads->config.realm) {
391 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
392 ads->ldap_port = 389;
395 if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap_ip), ads->server.realm, &reply ) ) {
396 d_fprintf(stderr, "CLDAP query failed!\n");
400 d_printf("Workgroup: %s\n", reply.netbios_domain);
409 static BOOL usergrp_display(char *field, void **values, void *data_area)
411 char **disp_fields = (char **) data_area;
413 if (!field) { /* must be end of record */
414 if (disp_fields[0]) {
415 if (!strchr_m(disp_fields[0], '$')) {
417 d_printf("%-21.21s %s\n",
418 disp_fields[0], disp_fields[1]);
420 d_printf("%s\n", disp_fields[0]);
423 SAFE_FREE(disp_fields[0]);
424 SAFE_FREE(disp_fields[1]);
427 if (!values) /* must be new field, indicate string field */
429 if (StrCaseCmp(field, "sAMAccountName") == 0) {
430 disp_fields[0] = SMB_STRDUP((char *) values[0]);
432 if (StrCaseCmp(field, "description") == 0)
433 disp_fields[1] = SMB_STRDUP((char *) values[0]);
437 static int net_ads_user_usage(int argc, const char **argv)
439 return net_help_user(argc, argv);
442 static int ads_user_add(int argc, const char **argv)
447 LDAPMessage *res=NULL;
451 if (argc < 1) return net_ads_user_usage(argc, argv);
453 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
457 status = ads_find_user_acct(ads, &res, argv[0]);
459 if (!ADS_ERR_OK(status)) {
460 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
464 if (ads_count_replies(ads, res)) {
465 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
470 ou_str = SMB_STRDUP(opt_container);
472 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
475 status = ads_add_user_acct(ads, argv[0], ou_str, opt_comment);
477 if (!ADS_ERR_OK(status)) {
478 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
483 /* if no password is to be set, we're done */
485 d_printf("User %s added\n", argv[0]);
490 /* try setting the password */
491 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
492 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
493 ads->auth.time_offset);
495 if (ADS_ERR_OK(status)) {
496 d_printf("User %s added\n", argv[0]);
501 /* password didn't set, delete account */
502 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
503 argv[0], ads_errstr(status));
504 ads_msgfree(ads, res);
505 status=ads_find_user_acct(ads, &res, argv[0]);
506 if (ADS_ERR_OK(status)) {
507 userdn = ads_get_dn(ads, res);
508 ads_del_dn(ads, userdn);
509 ads_memfree(ads, userdn);
514 ads_msgfree(ads, res);
520 static int ads_user_info(int argc, const char **argv)
525 const char *attrs[] = {"memberOf", NULL};
526 char *searchstring=NULL;
531 return net_ads_user_usage(argc, argv);
534 escaped_user = escape_ldap_string_alloc(argv[0]);
537 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
541 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
542 SAFE_FREE(escaped_user);
546 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
547 rc = ads_search(ads, &res, searchstring, attrs);
548 safe_free(searchstring);
550 if (!ADS_ERR_OK(rc)) {
551 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
553 SAFE_FREE(escaped_user);
557 grouplist = ldap_get_values((LDAP *)ads->ld,
558 (LDAPMessage *)res, "memberOf");
563 for (i=0;grouplist[i];i++) {
564 groupname = ldap_explode_dn(grouplist[i], 1);
565 d_printf("%s\n", groupname[0]);
566 ldap_value_free(groupname);
568 ldap_value_free(grouplist);
571 ads_msgfree(ads, res);
573 SAFE_FREE(escaped_user);
577 static int ads_user_delete(int argc, const char **argv)
581 LDAPMessage *res = NULL;
585 return net_ads_user_usage(argc, argv);
588 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
592 rc = ads_find_user_acct(ads, &res, argv[0]);
593 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
594 d_printf("User %s does not exist.\n", argv[0]);
595 ads_msgfree(ads, res);
599 userdn = ads_get_dn(ads, res);
600 ads_msgfree(ads, res);
601 rc = ads_del_dn(ads, userdn);
602 ads_memfree(ads, userdn);
603 if (ADS_ERR_OK(rc)) {
604 d_printf("User %s deleted\n", argv[0]);
608 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
614 int net_ads_user(int argc, const char **argv)
616 struct functable func[] = {
617 {"ADD", ads_user_add},
618 {"INFO", ads_user_info},
619 {"DELETE", ads_user_delete},
624 const char *shortattrs[] = {"sAMAccountName", NULL};
625 const char *longattrs[] = {"sAMAccountName", "description", NULL};
626 char *disp_fields[2] = {NULL, NULL};
629 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
633 if (opt_long_list_entries)
634 d_printf("\nUser name Comment"\
635 "\n-----------------------------\n");
637 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
639 "(objectCategory=user)",
640 opt_long_list_entries ? longattrs :
641 shortattrs, usergrp_display,
644 return ADS_ERR_OK(rc) ? 0 : -1;
647 return net_run_function(argc, argv, func, net_ads_user_usage);
650 static int net_ads_group_usage(int argc, const char **argv)
652 return net_help_group(argc, argv);
655 static int ads_group_add(int argc, const char **argv)
659 LDAPMessage *res=NULL;
664 return net_ads_group_usage(argc, argv);
667 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
671 status = ads_find_user_acct(ads, &res, argv[0]);
673 if (!ADS_ERR_OK(status)) {
674 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
678 if (ads_count_replies(ads, res)) {
679 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
684 ou_str = SMB_STRDUP(opt_container);
686 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
689 status = ads_add_group_acct(ads, argv[0], ou_str, opt_comment);
691 if (ADS_ERR_OK(status)) {
692 d_printf("Group %s added\n", argv[0]);
695 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
701 ads_msgfree(ads, res);
707 static int ads_group_delete(int argc, const char **argv)
711 LDAPMessage *res = NULL;
715 return net_ads_group_usage(argc, argv);
718 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
722 rc = ads_find_user_acct(ads, &res, argv[0]);
723 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
724 d_printf("Group %s does not exist.\n", argv[0]);
725 ads_msgfree(ads, res);
729 groupdn = ads_get_dn(ads, res);
730 ads_msgfree(ads, res);
731 rc = ads_del_dn(ads, groupdn);
732 ads_memfree(ads, groupdn);
733 if (ADS_ERR_OK(rc)) {
734 d_printf("Group %s deleted\n", argv[0]);
738 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
744 int net_ads_group(int argc, const char **argv)
746 struct functable func[] = {
747 {"ADD", ads_group_add},
748 {"DELETE", ads_group_delete},
753 const char *shortattrs[] = {"sAMAccountName", NULL};
754 const char *longattrs[] = {"sAMAccountName", "description", NULL};
755 char *disp_fields[2] = {NULL, NULL};
758 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
762 if (opt_long_list_entries)
763 d_printf("\nGroup name Comment"\
764 "\n-----------------------------\n");
765 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
767 "(objectCategory=group)",
768 opt_long_list_entries ? longattrs :
769 shortattrs, usergrp_display,
773 return ADS_ERR_OK(rc) ? 0 : -1;
775 return net_run_function(argc, argv, func, net_ads_group_usage);
778 static int net_ads_status(int argc, const char **argv)
784 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
788 rc = ads_find_machine_acct(ads, &res, global_myname());
789 if (!ADS_ERR_OK(rc)) {
790 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
795 if (ads_count_replies(ads, res) == 0) {
796 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
806 /*******************************************************************
807 Leave an AD domain. Windows XP disables the machine account.
808 We'll try the same. The old code would do an LDAP delete.
809 That only worked using the machine creds because added the machine
810 with full control to the computer object's ACL.
811 *******************************************************************/
813 static int net_ads_leave(int argc, const char **argv)
815 ADS_STRUCT *ads = NULL;
819 struct cli_state *cli = NULL;
821 DOM_SID *dom_sid = NULL;
823 if (!secrets_init()) {
824 DEBUG(1,("Failed to initialise secrets database\n"));
828 if (!(ctx = talloc_init("net_ads_leave"))) {
829 d_fprintf(stderr, "Could not initialise talloc context.\n");
833 /* The finds a DC and takes care of getting the
834 user creds if necessary */
836 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
840 /* make RPC calls here */
842 if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, &ads->ldap_ip,
843 ads->config.ldap_server_name)) )
848 saf_store( cli->server_domain, cli->desthost );
850 if ( !NT_STATUS_IS_OK(netdom_get_domain_sid( ctx, cli, &dom_sid )) ) {
854 status = netdom_leave_domain(ctx, cli, dom_sid);
856 /* Ty and delete it via LDAP - the old way we used to. */
858 adsret = ads_leave_realm(ads, global_myname());
859 if (ADS_ERR_OK(adsret)) {
860 d_printf("Deleted account for '%s' in realm '%s'\n",
861 global_myname(), ads->config.realm);
864 /* We couldn't delete it - see if the disable succeeded. */
865 if (NT_STATUS_IS_OK(status)) {
866 d_printf("Disabled account for '%s' in realm '%s'\n",
867 global_myname(), ads->config.realm);
870 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
871 global_myname(), ads->config.realm);
886 static NTSTATUS net_ads_join_ok(void)
888 ADS_STRUCT *ads = NULL;
891 if (!secrets_init()) {
892 DEBUG(1,("Failed to initialise secrets database\n"));
893 return NT_STATUS_ACCESS_DENIED;
896 net_use_machine_password();
898 status = ads_startup(True, &ads);
899 if (!ADS_ERR_OK(status)) {
900 return ads_ntstatus(status);
908 check that an existing join is OK
910 int net_ads_testjoin(int argc, const char **argv)
913 use_in_memory_ccache();
915 /* Display success or failure */
916 status = net_ads_join_ok();
917 if (!NT_STATUS_IS_OK(status)) {
918 fprintf(stderr,"Join to domain is not valid: %s\n",
919 get_friendly_nt_error_msg(status));
923 printf("Join is OK\n");
927 /*******************************************************************
928 Simple configu checks before beginning the join
929 ********************************************************************/
931 static NTSTATUS check_ads_config( void )
933 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
934 d_printf("Host is not configured as a member server.\n");
935 return NT_STATUS_INVALID_DOMAIN_ROLE;
938 if (strlen(global_myname()) > 15) {
939 d_printf("Our netbios name can be at most 15 chars long, "
940 "\"%s\" is %u chars long\n", global_myname(),
941 (unsigned int)strlen(global_myname()));
942 return NT_STATUS_NAME_TOO_LONG;
945 if ( lp_security() == SEC_ADS && !*lp_realm()) {
946 d_fprintf(stderr, "realm must be set in in smb.conf for ADS "
947 "join to succeed.\n");
948 return NT_STATUS_INVALID_PARAMETER;
951 if (!secrets_init()) {
952 DEBUG(1,("Failed to initialise secrets database\n"));
953 /* This is a good bet for failure of secrets_init ... */
954 return NT_STATUS_ACCESS_DENIED;
960 /*******************************************************************
962 ********************************************************************/
964 static NTSTATUS net_join_domain(TALLOC_CTX *ctx, const char *servername,
965 struct in_addr *ip, DOM_SID **dom_sid,
966 const char *password)
968 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
969 struct cli_state *cli = NULL;
971 ret = connect_to_ipc_krb5(&cli, ip, servername);
972 if ( !NT_STATUS_IS_OK(ret) ) {
976 saf_store( cli->server_domain, cli->desthost );
978 ret = netdom_get_domain_sid( ctx, cli, dom_sid );
979 if ( !NT_STATUS_IS_OK(ret) ) {
983 ret = netdom_join_domain( ctx, cli, *dom_sid, password, ND_TYPE_AD );
992 /*******************************************************************
993 Set a machines dNSHostName and servicePrincipalName attributes
994 ********************************************************************/
996 static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
998 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1001 const char *servicePrincipalName[3] = {NULL, NULL, NULL};
1004 LDAPMessage *res = NULL;
1005 char *dn_string = NULL;
1006 const char *machine_name = global_myname();
1009 if ( !machine_name ) {
1010 return ADS_ERROR(LDAP_NO_MEMORY);
1015 status = ads_find_machine_acct(ads_s, &res, machine_name);
1016 if (!ADS_ERR_OK(status))
1019 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1020 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1021 return ADS_ERROR(LDAP_NO_MEMORY);
1024 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1025 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1029 new_dn = talloc_strdup(ctx, dn_string);
1030 ads_memfree(ads_s, dn_string);
1032 return ADS_ERROR(LDAP_NO_MEMORY);
1035 /* Windows only creates HOST/shortname & HOST/fqdn. */
1037 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) )
1040 servicePrincipalName[0] = psp;
1042 name_to_fqdn(my_fqdn, machine_name);
1043 strlower_m(my_fqdn);
1044 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) )
1046 servicePrincipalName[1] = psp;
1048 if (!(mods = ads_init_mods(ctx))) {
1052 /* fields of primary importance */
1054 ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
1055 ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
1057 status = ads_gen_mod(ads_s, new_dn, mods);
1060 ads_msgfree(ads_s, res);
1065 /*******************************************************************
1066 Set a machines dNSHostName and servicePrincipalName attributes
1067 ********************************************************************/
1069 static ADS_STATUS net_set_machine_upn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, const char *upn )
1071 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1074 LDAPMessage *res = NULL;
1075 char *dn_string = NULL;
1076 const char *machine_name = global_myname();
1079 if ( !machine_name ) {
1080 return ADS_ERROR(LDAP_NO_MEMORY);
1085 status = ads_find_machine_acct(ads_s, &res, machine_name);
1086 if (!ADS_ERR_OK(status))
1089 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1090 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1091 return ADS_ERROR(LDAP_NO_MEMORY);
1094 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1095 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1099 new_dn = talloc_strdup(ctx, dn_string);
1100 ads_memfree(ads_s, dn_string);
1102 return ADS_ERROR(LDAP_NO_MEMORY);
1105 /* now do the mods */
1107 if (!(mods = ads_init_mods(ctx))) {
1111 /* fields of primary importance */
1113 ads_mod_str(ctx, &mods, "userPrincipalName", upn);
1115 status = ads_gen_mod(ads_s, new_dn, mods);
1118 ads_msgfree(ads_s, res);
1123 /*******************************************************************
1124 join a domain using ADS (LDAP mods)
1125 ********************************************************************/
1127 static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
1129 ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
1131 LDAPMessage *res = NULL;
1133 ou_str = ads_ou_string(ads, ou);
1134 if ((asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path)) == -1) {
1136 return ADS_ERROR(LDAP_NO_MEMORY);
1139 rc = ads_search_dn(ads, &res, dn, NULL);
1140 ads_msgfree(ads, res);
1142 if (ADS_ERR_OK(rc)) {
1143 /* Attempt to create the machine account and bail if this fails.
1144 Assume that the admin wants exactly what they requested */
1146 rc = ads_create_machine_acct( ads, global_myname(), dn );
1147 if ( rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS ) {
1152 SAFE_FREE( ou_str );
1158 /************************************************************************
1159 ************************************************************************/
1161 static BOOL net_derive_salting_principal( TALLOC_CTX *ctx, ADS_STRUCT *ads )
1167 LDAPMessage *res = NULL;
1168 const char *machine_name = global_myname();
1170 status = ads_domain_func_level( ads, &domain_func );
1171 if ( !ADS_ERR_OK(status) ) {
1172 DEBUG(2,("Failed to determine domain functional level!\n"));
1176 /* go ahead and setup the default salt */
1178 if ( (std_salt = kerberos_standard_des_salt()) == NULL ) {
1179 d_fprintf(stderr, "net_derive_salting_principal: failed to obtain stanard DES salt\n");
1183 fstrcpy( salt, std_salt );
1184 SAFE_FREE( std_salt );
1186 /* if it's a Windows functional domain, we have to look for the UPN */
1188 if ( domain_func == DS_DOMAIN_FUNCTION_2000 ) {
1192 status = ads_find_machine_acct(ads, &res, machine_name);
1193 if (!ADS_ERR_OK(status)) {
1197 if ( (count = ads_count_replies(ads, res)) != 1 ) {
1198 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1202 upn = ads_pull_string(ads, ctx, res, "userPrincipalName");
1204 fstrcpy( salt, upn );
1207 ads_msgfree(ads, res);
1210 return kerberos_secrets_store_des_salt( salt );
1213 /*******************************************************************
1214 Send a DNS update request
1215 *******************************************************************/
1217 #if defined(WITH_DNS_UPDATES)
1218 static BOOL net_update_dns( TALLOC_CTX *ctx, ADS_STRUCT *ads )
1221 struct in_addr *iplist = NULL;
1222 struct dns_rr_ns *nameservers = NULL;
1225 NTSTATUS dns_status;
1226 fstring machine_name;
1228 const char *dnsdomain;
1229 ADS_STRUCT *ads_s = NULL;
1231 name_to_fqdn( machine_name, global_myname() );
1232 strlower_m( machine_name );
1234 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1235 d_printf("No DNS domain configured for %s. Unable to perform DNS Update.\n",
1241 dns_status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1242 if ( !NT_STATUS_IS_OK(dns_status) || (ns_count == 0)) {
1243 DEBUG(3,("net_ads_join: Failed to find name server for the %s realm\n",
1244 ads->config.realm));
1248 /* Get our ip address (not the 127.0.0.x address but a real ip address) */
1250 num_addrs = get_my_ip_address( &iplist );
1251 if ( num_addrs <= 0 ) {
1252 DEBUG(4,("net_ads_join: Failed to find my non-loopback IP addresses!\n"));
1257 /* Drop the user creds */
1259 ads_kdestroy( NULL );
1261 ads_s = ads_init( ads->server.realm, ads->server.workgroup, ads->server.ldap_server );
1263 DEBUG(1,("net_ads_join: ads_init() failed!\n"));
1268 /* kinit with the machine password */
1270 asprintf( &ads_s->auth.user_name, "%s$", global_myname() );
1271 ads_s->auth.password = secrets_fetch_machine_password( lp_workgroup(), NULL, NULL );
1272 ads_s->auth.realm = SMB_STRDUP( lp_realm() );
1273 ads_kinit_password( ads_s );
1275 /* Now perform the dns update - we'll try non-secure and if we fail, we'll
1276 follow it up with a secure update */
1278 fstrcpy( dns_server, nameservers[0].hostname );
1280 ret = DoDNSUpdate(dns_server, dnsdomain, machine_name, iplist, num_addrs );
1282 DEBUG(1, ("Error creating dns update!\n"));
1286 SAFE_FREE( iplist );
1288 ads_destroy( &ads_s );
1295 /*******************************************************************
1296 utility function to parse an integer parameter from
1298 **********************************************************/
1299 static char* get_string_param( const char* param )
1303 if ( (p = strchr( param, '=' )) == NULL )
1309 /*******************************************************************
1310 ********************************************************************/
1312 static int net_ads_join_usage(int argc, const char **argv)
1314 d_printf("net ads join [options]\n");
1315 d_printf("Valid options:\n");
1316 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1317 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1318 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1319 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1320 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1325 /*******************************************************************
1326 ********************************************************************/
1328 int net_ads_join(int argc, const char **argv)
1330 ADS_STRUCT *ads = NULL;
1333 char *machine_account = NULL;
1334 const char *short_domain_name = NULL;
1335 char *tmp_password, *password;
1336 struct cldap_netlogon_reply cldap_reply;
1337 TALLOC_CTX *ctx = NULL;
1338 DOM_SID *domain_sid = NULL;
1339 BOOL createupn = False;
1340 const char *machineupn = NULL;
1341 const char *create_in_ou = NULL;
1344 nt_status = check_ads_config();
1345 if (!NT_STATUS_IS_OK(nt_status)) {
1346 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1350 status = ads_startup(True, &ads);
1351 if (!ADS_ERR_OK(status)) {
1352 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1353 nt_status = ads_ntstatus(status);
1357 if (strcmp(ads->config.realm, lp_realm()) != 0) {
1358 d_fprintf(stderr, "realm of remote server (%s) and realm in smb.conf "
1359 "(%s) DO NOT match. Aborting join\n", ads->config.realm,
1361 nt_status = NT_STATUS_INVALID_PARAMETER;
1365 if (!(ctx = talloc_init("net_ads_join"))) {
1366 d_fprintf(stderr, "Could not initialise talloc context.\n");
1367 nt_status = NT_STATUS_NO_MEMORY;
1371 /* process additional command line args */
1373 for ( i=0; i<argc; i++ ) {
1374 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1376 machineupn = get_string_param(argv[i]);
1378 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1379 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1380 d_fprintf(stderr, "Please supply a valid OU path\n");
1381 nt_status = NT_STATUS_INVALID_PARAMETER;
1386 d_fprintf(stderr, "Bad option: %s\n", argv[i]);
1387 nt_status = NT_STATUS_INVALID_PARAMETER;
1392 /* If we were given an OU, try to create the machine in
1393 the OU account first and then do the normal RPC join */
1395 if ( create_in_ou ) {
1396 status = net_precreate_machine_acct( ads, create_in_ou );
1397 if ( !ADS_ERR_OK(status) ) {
1398 d_fprintf( stderr, "Failed to pre-create the machine object "
1399 "in OU %s.\n", argv[0]);
1400 DEBUG(1, ("error calling net_precreate_machine_acct: %s\n",
1401 ads_errstr(status)));
1402 nt_status = ads_ntstatus(status);
1407 /* Do the domain join here */
1409 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1410 password = talloc_strdup(ctx, tmp_password);
1412 nt_status = net_join_domain(ctx, ads->config.ldap_server_name,
1413 &ads->ldap_ip, &domain_sid, password);
1414 if ( !NT_STATUS_IS_OK(nt_status) ) {
1415 DEBUG(1, ("call of net_join_domain failed: %s\n",
1416 get_friendly_nt_error_msg(nt_status)));
1420 /* Check the short name of the domain */
1422 ZERO_STRUCT( cldap_reply );
1424 if ( ads_cldap_netlogon( ads->config.ldap_server_name,
1425 ads->server.realm, &cldap_reply ) )
1427 short_domain_name = talloc_strdup( ctx, cldap_reply.netbios_domain );
1428 if ( !strequal(lp_workgroup(), short_domain_name) ) {
1429 d_printf("The workgroup in smb.conf does not match the short\n");
1430 d_printf("domain name obtained from the server.\n");
1431 d_printf("Using the name [%s] from the server.\n", short_domain_name);
1432 d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
1435 short_domain_name = lp_workgroup();
1438 d_printf("Using short domain name -- %s\n", short_domain_name);
1440 /* HACK ALERT! Store the sid and password under both the lp_workgroup()
1441 value from smb.conf and the string returned from the server. The former is
1442 neede to bootstrap winbindd's first connection to the DC to get the real
1443 short domain name --jerry */
1445 if ( (netdom_store_machine_account( lp_workgroup(), domain_sid, password ) == -1)
1446 || (netdom_store_machine_account( short_domain_name, domain_sid, password ) == -1) )
1448 /* issue an internal error here for now.
1449 * everything else would mean changing tdb routines. */
1450 nt_status = NT_STATUS_INTERNAL_ERROR;
1454 /* Verify that everything is ok */
1456 if ( net_rpc_join_ok(short_domain_name, ads->config.ldap_server_name, &ads->ldap_ip) != 0 ) {
1457 d_fprintf(stderr, "Failed to verify membership in domain!\n");
1461 /* create the dNSHostName & servicePrincipalName values */
1463 status = net_set_machine_spn( ctx, ads );
1464 if ( !ADS_ERR_OK(status) ) {
1466 d_fprintf(stderr, "Failed to set servicePrincipalNames. Please ensure that\n");
1467 d_fprintf(stderr, "the DNS domain of this server matches the AD domain,\n");
1468 d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n");
1470 /* Disable the machine account in AD. Better to fail than to leave
1471 a confused admin. */
1473 if ( net_ads_leave( 0, NULL ) != 0 ) {
1474 d_fprintf( stderr, "Failed to disable machine account in AD. Please do so manually.\n");
1477 /* clear out the machine password */
1479 netdom_store_machine_account( lp_workgroup(), domain_sid, "" );
1480 netdom_store_machine_account( short_domain_name, domain_sid, "" );
1482 nt_status = ads_ntstatus(status);
1486 if ( !net_derive_salting_principal( ctx, ads ) ) {
1487 DEBUG(1,("Failed to determine salting principal\n"));
1494 /* default to using the short UPN name */
1495 if ( !machineupn ) {
1496 snprintf( upn, sizeof(upn), "host/%s@%s", global_myname(),
1497 ads->config.realm );
1501 status = net_set_machine_upn( ctx, ads, machineupn );
1502 if ( !ADS_ERR_OK(status) ) {
1503 d_fprintf(stderr, "Failed to set userPrincipalName. Are you a Domain Admin?\n");
1507 /* Now build the keytab, using the same ADS connection */
1508 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
1509 DEBUG(1,("Error creating host keytab!\n"));
1512 #if defined(WITH_DNS_UPDATES)
1513 /* We enter this block with user creds */
1515 if ( !net_update_dns( ctx, ads ) ) {
1516 d_fprintf( stderr, "DNS update failed!\n" );
1519 /* exit from this block using machine creds */
1522 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
1524 SAFE_FREE(machine_account);
1531 /* issue an overall failure message at the end. */
1532 d_printf("Failed to join domain: %s\n", get_friendly_nt_error_msg(nt_status));
1534 SAFE_FREE(machine_account);
1542 /*******************************************************************
1543 ********************************************************************/
1545 static int net_ads_dns_usage(int argc, const char **argv)
1547 #if defined(WITH_DNS_UPDATES)
1548 d_printf("net ads dns <command>\n");
1549 d_printf("Valid commands:\n");
1550 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1554 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1559 /*******************************************************************
1560 ********************************************************************/
1562 static int net_ads_dns(int argc, const char **argv)
1564 #if defined(WITH_DNS_UPDATES)
1568 BOOL register_dns = False;
1571 status = ads_startup(True, &ads);
1572 if ( !ADS_ERR_OK(status) ) {
1573 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1577 if (!(ctx = talloc_init("net_ads_dns"))) {
1578 DEBUG(0, ("Could not initialise talloc context\n"));
1582 /* process additional command line args */
1584 for ( i=0; i<argc; i++ ) {
1585 if ( strequal(argv[i], "register") ) {
1586 register_dns = True;
1589 d_fprintf(stderr, "Bad option: %s\n", argv[i]);
1594 if ( !net_update_dns( ctx, ads ) ) {
1595 d_fprintf( stderr, "DNS update failed!\n" );
1596 ads_destroy( &ads );
1601 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1608 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1613 /*******************************************************************
1614 ********************************************************************/
1616 int net_ads_printer_usage(int argc, const char **argv)
1619 "\nnet ads printer search <printer>"
1620 "\n\tsearch for a printer in the directory\n"
1621 "\nnet ads printer info <printer> <server>"
1622 "\n\tlookup info in directory for printer on server"
1623 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1624 "\nnet ads printer publish <printername>"
1625 "\n\tpublish printer in directory"
1626 "\n\t(note: printer name is required)\n"
1627 "\nnet ads printer remove <printername>"
1628 "\n\tremove printer from directory"
1629 "\n\t(note: printer name is required)\n");
1633 /*******************************************************************
1634 ********************************************************************/
1636 static int net_ads_printer_search(int argc, const char **argv)
1640 LDAPMessage *res = NULL;
1642 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1646 rc = ads_find_printers(ads, &res);
1648 if (!ADS_ERR_OK(rc)) {
1649 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1650 ads_msgfree(ads, res);
1655 if (ads_count_replies(ads, res) == 0) {
1656 d_fprintf(stderr, "No results found\n");
1657 ads_msgfree(ads, res);
1663 ads_msgfree(ads, res);
1668 static int net_ads_printer_info(int argc, const char **argv)
1672 const char *servername, *printername;
1673 LDAPMessage *res = NULL;
1675 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1680 printername = argv[0];
1686 servername = argv[1];
1688 servername = global_myname();
1691 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1693 if (!ADS_ERR_OK(rc)) {
1694 d_fprintf(stderr, "Server '%s' not found: %s\n",
1695 servername, ads_errstr(rc));
1696 ads_msgfree(ads, res);
1701 if (ads_count_replies(ads, res) == 0) {
1702 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1703 ads_msgfree(ads, res);
1709 ads_msgfree(ads, res);
1715 void do_drv_upgrade_printer(int msg_type, struct process_id src,
1716 void *buf, size_t len)
1721 static int net_ads_printer_publish(int argc, const char **argv)
1725 const char *servername, *printername;
1726 struct cli_state *cli;
1727 struct rpc_pipe_client *pipe_hnd;
1728 struct in_addr server_ip;
1730 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1731 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1732 char *prt_dn, *srv_dn, **srv_cn;
1733 LDAPMessage *res = NULL;
1735 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1740 return net_ads_printer_usage(argc, argv);
1743 printername = argv[0];
1746 servername = argv[1];
1748 servername = global_myname();
1751 /* Get printer data from SPOOLSS */
1753 resolve_name(servername, &server_ip, 0x20);
1755 nt_status = cli_full_connection(&cli, global_myname(), servername,
1758 opt_user_name, opt_workgroup,
1759 opt_password ? opt_password : "",
1760 CLI_FULL_CONNECTION_USE_KERBEROS,
1763 if (NT_STATUS_IS_ERR(nt_status)) {
1764 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1765 "for %s\n", servername, printername);
1770 /* Publish on AD server */
1772 ads_find_machine_acct(ads, &res, servername);
1774 if (ads_count_replies(ads, res) == 0) {
1775 d_fprintf(stderr, "Could not find machine account for server %s\n",
1781 srv_dn = ldap_get_dn((LDAP *)ads->ld, (LDAPMessage *)res);
1782 srv_cn = ldap_explode_dn(srv_dn, 1);
1784 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
1786 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1788 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1794 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1800 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1801 if (!ADS_ERR_OK(rc)) {
1802 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1807 d_printf("published printer\n");
1813 static int net_ads_printer_remove(int argc, const char **argv)
1817 const char *servername;
1819 LDAPMessage *res = NULL;
1821 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1826 return net_ads_printer_usage(argc, argv);
1830 servername = argv[1];
1832 servername = global_myname();
1835 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1837 if (!ADS_ERR_OK(rc)) {
1838 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1839 ads_msgfree(ads, res);
1844 if (ads_count_replies(ads, res) == 0) {
1845 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1846 ads_msgfree(ads, res);
1851 prt_dn = ads_get_dn(ads, res);
1852 ads_msgfree(ads, res);
1853 rc = ads_del_dn(ads, prt_dn);
1854 ads_memfree(ads, prt_dn);
1856 if (!ADS_ERR_OK(rc)) {
1857 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1866 static int net_ads_printer(int argc, const char **argv)
1868 struct functable func[] = {
1869 {"SEARCH", net_ads_printer_search},
1870 {"INFO", net_ads_printer_info},
1871 {"PUBLISH", net_ads_printer_publish},
1872 {"REMOVE", net_ads_printer_remove},
1876 return net_run_function(argc, argv, func, net_ads_printer_usage);
1880 static int net_ads_password(int argc, const char **argv)
1883 const char *auth_principal = opt_user_name;
1884 const char *auth_password = opt_password;
1886 char *new_password = NULL;
1891 if (opt_user_name == NULL || opt_password == NULL) {
1892 d_fprintf(stderr, "You must supply an administrator username/password\n");
1897 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1902 if (!strchr_m(user, '@')) {
1903 asprintf(&c, "%s@%s", argv[0], lp_realm());
1907 use_in_memory_ccache();
1908 c = strchr_m(auth_principal, '@');
1915 /* use the realm so we can eventually change passwords for users
1916 in realms other than default */
1917 if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
1921 /* we don't actually need a full connect, but it's the easy way to
1922 fill in the KDC's addresss */
1925 if (!ads || !ads->config.realm) {
1926 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1931 new_password = (char *)argv[1];
1933 asprintf(&prompt, "Enter new password for %s:", user);
1934 new_password = getpass(prompt);
1938 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1939 auth_password, user, new_password, ads->auth.time_offset);
1940 if (!ADS_ERR_OK(ret)) {
1941 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1946 d_printf("Password change for %s completed.\n", user);
1952 int net_ads_changetrustpw(int argc, const char **argv)
1955 char *host_principal;
1959 if (!secrets_init()) {
1960 DEBUG(1,("Failed to initialise secrets database\n"));
1964 net_use_machine_password();
1966 use_in_memory_ccache();
1968 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1972 fstrcpy(my_name, global_myname());
1973 strlower_m(my_name);
1974 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1975 d_printf("Changing password for principal: %s\n", host_principal);
1977 ret = ads_change_trust_account_password(ads, host_principal);
1979 if (!ADS_ERR_OK(ret)) {
1980 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1982 SAFE_FREE(host_principal);
1986 d_printf("Password change for principal %s succeeded.\n", host_principal);
1988 if (lp_use_kerberos_keytab()) {
1989 d_printf("Attempting to update system keytab with new password.\n");
1990 if (ads_keytab_create_default(ads)) {
1991 d_printf("Failed to update system keytab.\n");
1996 SAFE_FREE(host_principal);
2002 help for net ads search
2004 static int net_ads_search_usage(int argc, const char **argv)
2007 "\nnet ads search <expression> <attributes...>\n"\
2008 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2009 "The expression is a standard LDAP search expression, and the\n"\
2010 "attributes are a list of LDAP fields to show in the results\n\n"\
2011 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2013 net_common_flags_usage(argc, argv);
2019 general ADS search function. Useful in diagnosing problems in ADS
2021 static int net_ads_search(int argc, const char **argv)
2025 const char *ldap_exp;
2027 LDAPMessage *res = NULL;
2030 return net_ads_search_usage(argc, argv);
2033 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2040 rc = ads_do_search_all(ads, ads->config.bind_path,
2042 ldap_exp, attrs, &res);
2043 if (!ADS_ERR_OK(rc)) {
2044 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2049 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2051 /* dump the results */
2054 ads_msgfree(ads, res);
2062 help for net ads search
2064 static int net_ads_dn_usage(int argc, const char **argv)
2067 "\nnet ads dn <dn> <attributes...>\n"\
2068 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2069 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
2070 "to show in the results\n\n"\
2071 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2073 net_common_flags_usage(argc, argv);
2079 general ADS search function. Useful in diagnosing problems in ADS
2081 static int net_ads_dn(int argc, const char **argv)
2087 LDAPMessage *res = NULL;
2090 return net_ads_dn_usage(argc, argv);
2093 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2100 rc = ads_do_search_all(ads, dn,
2102 "(objectclass=*)", attrs, &res);
2103 if (!ADS_ERR_OK(rc)) {
2104 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2109 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2111 /* dump the results */
2114 ads_msgfree(ads, res);
2121 help for net ads sid search
2123 static int net_ads_sid_usage(int argc, const char **argv)
2126 "\nnet ads sid <sid> <attributes...>\n"\
2127 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2128 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
2129 "to show in the results\n\n"\
2130 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2132 net_common_flags_usage(argc, argv);
2138 general ADS search function. Useful in diagnosing problems in ADS
2140 static int net_ads_sid(int argc, const char **argv)
2144 const char *sid_string;
2146 LDAPMessage *res = NULL;
2150 return net_ads_sid_usage(argc, argv);
2153 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2157 sid_string = argv[0];
2160 if (!string_to_sid(&sid, sid_string)) {
2161 d_fprintf(stderr, "could not convert sid\n");
2166 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2167 if (!ADS_ERR_OK(rc)) {
2168 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2173 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2175 /* dump the results */
2178 ads_msgfree(ads, res);
2185 static int net_ads_keytab_usage(int argc, const char **argv)
2188 "net ads keytab <COMMAND>\n"\
2189 "<COMMAND> can be either:\n"\
2190 " CREATE Creates a fresh keytab\n"\
2191 " ADD Adds new service principal\n"\
2192 " FLUSH Flushes out all keytab entries\n"\
2193 " HELP Prints this help message\n"\
2194 "The ADD command will take arguments, the other commands\n"\
2195 "will not take any arguments. The arguments given to ADD\n"\
2196 "should be a list of principals to add. For example, \n"\
2197 " net ads keytab add srv1 srv2\n"\
2198 "will add principals for the services srv1 and srv2 to the\n"\
2199 "system's keytab.\n"\
2205 static int net_ads_keytab_flush(int argc, const char **argv)
2210 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2213 ret = ads_keytab_flush(ads);
2218 static int net_ads_keytab_add(int argc, const char **argv)
2224 d_printf("Processing principals to add...\n");
2225 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2228 for (i = 0; i < argc; i++) {
2229 ret |= ads_keytab_add_entry(ads, argv[i]);
2235 static int net_ads_keytab_create(int argc, const char **argv)
2240 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2243 ret = ads_keytab_create_default(ads);
2248 int net_ads_keytab(int argc, const char **argv)
2250 struct functable func[] = {
2251 {"CREATE", net_ads_keytab_create},
2252 {"ADD", net_ads_keytab_add},
2253 {"FLUSH", net_ads_keytab_flush},
2254 {"HELP", net_ads_keytab_usage},
2258 if (!lp_use_kerberos_keytab()) {
2259 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2260 use keytab functions.\n");
2263 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2266 int net_ads_help(int argc, const char **argv)
2268 struct functable func[] = {
2269 {"USER", net_ads_user_usage},
2270 {"GROUP", net_ads_group_usage},
2271 {"PRINTER", net_ads_printer_usage},
2272 {"SEARCH", net_ads_search_usage},
2273 {"INFO", net_ads_info},
2274 {"JOIN", net_ads_join_usage},
2275 {"DNS", net_ads_dns_usage},
2276 {"LEAVE", net_ads_leave},
2277 {"STATUS", net_ads_status},
2278 {"PASSWORD", net_ads_password},
2279 {"CHANGETRUSTPW", net_ads_changetrustpw},
2283 return net_run_function(argc, argv, func, net_ads_usage);
2286 int net_ads(int argc, const char **argv)
2288 struct functable func[] = {
2289 {"INFO", net_ads_info},
2290 {"JOIN", net_ads_join},
2291 {"TESTJOIN", net_ads_testjoin},
2292 {"LEAVE", net_ads_leave},
2293 {"STATUS", net_ads_status},
2294 {"USER", net_ads_user},
2295 {"GROUP", net_ads_group},
2296 {"DNS", net_ads_dns},
2297 {"PASSWORD", net_ads_password},
2298 {"CHANGETRUSTPW", net_ads_changetrustpw},
2299 {"PRINTER", net_ads_printer},
2300 {"SEARCH", net_ads_search},
2302 {"SID", net_ads_sid},
2303 {"WORKGROUP", net_ads_workgroup},
2304 {"LOOKUP", net_ads_lookup},
2305 {"KEYTAB", net_ads_keytab},
2306 {"GPO", net_ads_gpo},
2307 {"HELP", net_ads_help},
2311 return net_run_function(argc, argv, func, net_ads_usage);
2316 static int net_ads_noads(void)
2318 d_fprintf(stderr, "ADS support not compiled in\n");
2322 int net_ads_keytab(int argc, const char **argv)
2324 return net_ads_noads();
2327 int net_ads_usage(int argc, const char **argv)
2329 return net_ads_noads();
2332 int net_ads_help(int argc, const char **argv)
2334 return net_ads_noads();
2337 int net_ads_changetrustpw(int argc, const char **argv)
2339 return net_ads_noads();
2342 int net_ads_join(int argc, const char **argv)
2344 return net_ads_noads();
2347 int net_ads_user(int argc, const char **argv)
2349 return net_ads_noads();
2352 int net_ads_group(int argc, const char **argv)
2354 return net_ads_noads();
2357 /* this one shouldn't display a message */
2358 int net_ads_check(void)
2363 int net_ads_check_our_domain(void)
2368 int net_ads(int argc, const char **argv)
2370 return net_ads_usage(argc, argv);
2373 #endif /* WITH_ADS */