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 (!ads_closest_dc(ads)) {
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;
822 char *short_domain_name = NULL;
824 if (!secrets_init()) {
825 DEBUG(1,("Failed to initialise secrets database\n"));
829 if (!(ctx = talloc_init("net_ads_leave"))) {
830 d_fprintf(stderr, "Could not initialise talloc context.\n");
834 /* The finds a DC and takes care of getting the
835 user creds if necessary */
837 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
841 /* make RPC calls here */
843 if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, &ads->ldap_ip,
844 ads->config.ldap_server_name)) )
849 if ( !NT_STATUS_IS_OK(netdom_get_domain_sid( ctx, cli, &short_domain_name, &dom_sid )) ) {
853 saf_delete( short_domain_name );
855 status = netdom_leave_domain(ctx, cli, dom_sid);
857 /* Try and delete it via LDAP - the old way we used to. */
859 adsret = ads_leave_realm(ads, global_myname());
860 if (ADS_ERR_OK(adsret)) {
861 d_printf("Deleted account for '%s' in realm '%s'\n",
862 global_myname(), ads->config.realm);
865 /* We couldn't delete it - see if the disable succeeded. */
866 if (NT_STATUS_IS_OK(status)) {
867 d_printf("Disabled account for '%s' in realm '%s'\n",
868 global_myname(), ads->config.realm);
871 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
872 global_myname(), ads->config.realm);
887 static NTSTATUS net_ads_join_ok(void)
889 ADS_STRUCT *ads = NULL;
892 if (!secrets_init()) {
893 DEBUG(1,("Failed to initialise secrets database\n"));
894 return NT_STATUS_ACCESS_DENIED;
897 net_use_machine_password();
899 status = ads_startup(True, &ads);
900 if (!ADS_ERR_OK(status)) {
901 return ads_ntstatus(status);
909 check that an existing join is OK
911 int net_ads_testjoin(int argc, const char **argv)
914 use_in_memory_ccache();
916 /* Display success or failure */
917 status = net_ads_join_ok();
918 if (!NT_STATUS_IS_OK(status)) {
919 fprintf(stderr,"Join to domain is not valid: %s\n",
920 get_friendly_nt_error_msg(status));
924 printf("Join is OK\n");
928 /*******************************************************************
929 Simple configu checks before beginning the join
930 ********************************************************************/
932 static NTSTATUS check_ads_config( void )
934 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
935 d_printf("Host is not configured as a member server.\n");
936 return NT_STATUS_INVALID_DOMAIN_ROLE;
939 if (strlen(global_myname()) > 15) {
940 d_printf("Our netbios name can be at most 15 chars long, "
941 "\"%s\" is %u chars long\n", global_myname(),
942 (unsigned int)strlen(global_myname()));
943 return NT_STATUS_NAME_TOO_LONG;
946 if ( lp_security() == SEC_ADS && !*lp_realm()) {
947 d_fprintf(stderr, "realm must be set in in smb.conf for ADS "
948 "join to succeed.\n");
949 return NT_STATUS_INVALID_PARAMETER;
952 if (!secrets_init()) {
953 DEBUG(1,("Failed to initialise secrets database\n"));
954 /* This is a good bet for failure of secrets_init ... */
955 return NT_STATUS_ACCESS_DENIED;
961 /*******************************************************************
963 ********************************************************************/
965 static NTSTATUS net_join_domain(TALLOC_CTX *ctx, const char *servername,
966 struct in_addr *ip, char **domain,
968 const char *password)
970 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
971 struct cli_state *cli = NULL;
973 ret = connect_to_ipc_krb5(&cli, ip, servername);
974 if ( !NT_STATUS_IS_OK(ret) ) {
978 ret = netdom_get_domain_sid( ctx, cli, domain, dom_sid );
979 if ( !NT_STATUS_IS_OK(ret) ) {
983 /* cli->server_domain is not filled in when using krb5
986 saf_store( *domain, cli->desthost );
988 ret = netdom_join_domain( ctx, cli, *dom_sid, password, ND_TYPE_AD );
997 /*******************************************************************
998 Set a machines dNSHostName and servicePrincipalName attributes
999 ********************************************************************/
1001 static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
1003 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1006 const char *servicePrincipalName[3] = {NULL, NULL, NULL};
1009 LDAPMessage *res = NULL;
1010 char *dn_string = NULL;
1011 const char *machine_name = global_myname();
1014 if ( !machine_name ) {
1015 return ADS_ERROR(LDAP_NO_MEMORY);
1020 status = ads_find_machine_acct(ads_s, &res, machine_name);
1021 if (!ADS_ERR_OK(status))
1024 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1025 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1026 return ADS_ERROR(LDAP_NO_MEMORY);
1029 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1030 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1034 new_dn = talloc_strdup(ctx, dn_string);
1035 ads_memfree(ads_s, dn_string);
1037 return ADS_ERROR(LDAP_NO_MEMORY);
1040 /* Windows only creates HOST/shortname & HOST/fqdn. */
1042 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) )
1045 servicePrincipalName[0] = psp;
1047 name_to_fqdn(my_fqdn, machine_name);
1048 strlower_m(my_fqdn);
1049 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) )
1051 servicePrincipalName[1] = psp;
1053 if (!(mods = ads_init_mods(ctx))) {
1057 /* fields of primary importance */
1059 ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
1060 ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
1062 status = ads_gen_mod(ads_s, new_dn, mods);
1065 ads_msgfree(ads_s, res);
1070 /*******************************************************************
1071 Set a machines dNSHostName and servicePrincipalName attributes
1072 ********************************************************************/
1074 static ADS_STATUS net_set_machine_upn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, const char *upn )
1076 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1079 LDAPMessage *res = NULL;
1080 char *dn_string = NULL;
1081 const char *machine_name = global_myname();
1084 if ( !machine_name ) {
1085 return ADS_ERROR(LDAP_NO_MEMORY);
1090 status = ads_find_machine_acct(ads_s, &res, machine_name);
1091 if (!ADS_ERR_OK(status))
1094 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1095 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1096 return ADS_ERROR(LDAP_NO_MEMORY);
1099 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1100 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1104 new_dn = talloc_strdup(ctx, dn_string);
1105 ads_memfree(ads_s, dn_string);
1107 return ADS_ERROR(LDAP_NO_MEMORY);
1110 /* now do the mods */
1112 if (!(mods = ads_init_mods(ctx))) {
1116 /* fields of primary importance */
1118 ads_mod_str(ctx, &mods, "userPrincipalName", upn);
1120 status = ads_gen_mod(ads_s, new_dn, mods);
1123 ads_msgfree(ads_s, res);
1128 /*******************************************************************
1129 join a domain using ADS (LDAP mods)
1130 ********************************************************************/
1132 static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
1134 ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
1136 LDAPMessage *res = NULL;
1138 ou_str = ads_ou_string(ads, ou);
1139 if ((asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path)) == -1) {
1141 return ADS_ERROR(LDAP_NO_MEMORY);
1144 rc = ads_search_dn(ads, &res, dn, NULL);
1145 ads_msgfree(ads, res);
1147 if (ADS_ERR_OK(rc)) {
1148 /* Attempt to create the machine account and bail if this fails.
1149 Assume that the admin wants exactly what they requested */
1151 rc = ads_create_machine_acct( ads, global_myname(), dn );
1152 if ( rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS ) {
1157 SAFE_FREE( ou_str );
1163 /************************************************************************
1164 ************************************************************************/
1166 static BOOL net_derive_salting_principal( TALLOC_CTX *ctx, ADS_STRUCT *ads )
1172 LDAPMessage *res = NULL;
1173 const char *machine_name = global_myname();
1175 status = ads_domain_func_level( ads, &domain_func );
1176 if ( !ADS_ERR_OK(status) ) {
1177 DEBUG(2,("Failed to determine domain functional level!\n"));
1181 /* go ahead and setup the default salt */
1183 if ( (std_salt = kerberos_standard_des_salt()) == NULL ) {
1184 d_fprintf(stderr, "net_derive_salting_principal: failed to obtain stanard DES salt\n");
1188 fstrcpy( salt, std_salt );
1189 SAFE_FREE( std_salt );
1191 /* if it's a Windows functional domain, we have to look for the UPN */
1193 if ( domain_func == DS_DOMAIN_FUNCTION_2000 ) {
1197 status = ads_find_machine_acct(ads, &res, machine_name);
1198 if (!ADS_ERR_OK(status)) {
1202 if ( (count = ads_count_replies(ads, res)) != 1 ) {
1203 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1207 upn = ads_pull_string(ads, ctx, res, "userPrincipalName");
1209 fstrcpy( salt, upn );
1212 ads_msgfree(ads, res);
1215 return kerberos_secrets_store_des_salt( salt );
1218 /*******************************************************************
1219 Send a DNS update request
1220 *******************************************************************/
1222 #if defined(WITH_DNS_UPDATES)
1224 DNS_ERROR DoDNSUpdate(ADS_STRUCT *ads, char *pszServerName,
1225 const char *pszDomainName,
1226 const char *pszHostName,
1227 const struct in_addr *iplist, int num_addrs );
1230 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1231 const char *machine_name,
1232 const struct in_addr *addrs,
1235 struct dns_rr_ns *nameservers = NULL;
1237 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1240 const char *dnsdomain;
1242 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1243 d_printf("No DNS domain configured for %s. "
1244 "Unable to perform DNS Update.\n", machine_name);
1245 status = NT_STATUS_INVALID_PARAMETER;
1250 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1251 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1252 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1253 "realm\n", ads->config.realm));
1257 /* Now perform the dns update - we'll try non-secure and if we fail,
1258 we'll follow it up with a secure update */
1260 fstrcpy( dns_server, nameservers[0].hostname );
1262 dns_err = DoDNSUpdate(ads, dns_server, dnsdomain, machine_name, addrs, num_addrs);
1263 if (!ERR_DNS_IS_OK(dns_err)) {
1264 status = NT_STATUS_UNSUCCESSFUL;
1271 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1274 struct in_addr *iplist = NULL;
1275 fstring machine_name;
1278 name_to_fqdn( machine_name, global_myname() );
1279 strlower_m( machine_name );
1281 /* Get our ip address (not the 127.0.0.x address but a real ip
1284 num_addrs = get_my_ip_address( &iplist );
1285 if ( num_addrs <= 0 ) {
1286 DEBUG(4,("net_ads_join: Failed to find my non-loopback IP "
1288 return NT_STATUS_INVALID_PARAMETER;
1291 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1293 SAFE_FREE( iplist );
1299 /*******************************************************************
1300 utility function to parse an integer parameter from
1302 **********************************************************/
1303 static char* get_string_param( const char* param )
1307 if ( (p = strchr( param, '=' )) == NULL )
1313 /*******************************************************************
1314 ********************************************************************/
1316 static int net_ads_join_usage(int argc, const char **argv)
1318 d_printf("net ads join [options]\n");
1319 d_printf("Valid options:\n");
1320 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1321 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1322 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1323 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1324 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1329 /*******************************************************************
1330 ********************************************************************/
1332 int net_ads_join(int argc, const char **argv)
1334 ADS_STRUCT *ads = NULL;
1337 char *machine_account = NULL;
1338 char *short_domain_name = NULL;
1339 char *tmp_password, *password;
1340 TALLOC_CTX *ctx = NULL;
1341 DOM_SID *domain_sid = NULL;
1342 BOOL createupn = False;
1343 const char *machineupn = NULL;
1344 const char *create_in_ou = NULL;
1347 nt_status = check_ads_config();
1348 if (!NT_STATUS_IS_OK(nt_status)) {
1349 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1353 status = ads_startup(True, &ads);
1354 if (!ADS_ERR_OK(status)) {
1355 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1356 nt_status = ads_ntstatus(status);
1360 if (strcmp(ads->config.realm, lp_realm()) != 0) {
1361 d_fprintf(stderr, "realm of remote server (%s) and realm in smb.conf "
1362 "(%s) DO NOT match. Aborting join\n", ads->config.realm,
1364 nt_status = NT_STATUS_INVALID_PARAMETER;
1368 if (!(ctx = talloc_init("net_ads_join"))) {
1369 d_fprintf(stderr, "Could not initialise talloc context.\n");
1370 nt_status = NT_STATUS_NO_MEMORY;
1374 /* process additional command line args */
1376 for ( i=0; i<argc; i++ ) {
1377 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1379 machineupn = get_string_param(argv[i]);
1381 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1382 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1383 d_fprintf(stderr, "Please supply a valid OU path\n");
1384 nt_status = NT_STATUS_INVALID_PARAMETER;
1389 d_fprintf(stderr, "Bad option: %s\n", argv[i]);
1390 nt_status = NT_STATUS_INVALID_PARAMETER;
1395 /* If we were given an OU, try to create the machine in
1396 the OU account first and then do the normal RPC join */
1398 if ( create_in_ou ) {
1399 status = net_precreate_machine_acct( ads, create_in_ou );
1400 if ( !ADS_ERR_OK(status) ) {
1401 d_fprintf( stderr, "Failed to pre-create the machine object "
1402 "in OU %s.\n", argv[0]);
1403 DEBUG(1, ("error calling net_precreate_machine_acct: %s\n",
1404 ads_errstr(status)));
1405 nt_status = ads_ntstatus(status);
1410 /* Do the domain join here */
1412 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1413 password = talloc_strdup(ctx, tmp_password);
1415 nt_status = net_join_domain(ctx, ads->config.ldap_server_name,
1416 &ads->ldap_ip, &short_domain_name, &domain_sid, password);
1417 if ( !NT_STATUS_IS_OK(nt_status) ) {
1418 DEBUG(1, ("call of net_join_domain failed: %s\n",
1419 get_friendly_nt_error_msg(nt_status)));
1423 /* Check the short name of the domain */
1425 if ( !strequal(lp_workgroup(), short_domain_name) ) {
1426 d_printf("The workgroup in smb.conf does not match the short\n");
1427 d_printf("domain name obtained from the server.\n");
1428 d_printf("Using the name [%s] from the server.\n", short_domain_name);
1429 d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
1432 d_printf("Using short domain name -- %s\n", short_domain_name);
1434 /* HACK ALERT! Store the sid and password under both the lp_workgroup()
1435 value from smb.conf and the string returned from the server. The former is
1436 neede to bootstrap winbindd's first connection to the DC to get the real
1437 short domain name --jerry */
1439 if ( (netdom_store_machine_account( lp_workgroup(), domain_sid, password ) == -1)
1440 || (netdom_store_machine_account( short_domain_name, domain_sid, password ) == -1) )
1442 /* issue an internal error here for now.
1443 * everything else would mean changing tdb routines. */
1444 nt_status = NT_STATUS_INTERNAL_ERROR;
1448 /* Verify that everything is ok */
1450 if ( net_rpc_join_ok(short_domain_name, ads->config.ldap_server_name, &ads->ldap_ip) != 0 ) {
1451 d_fprintf(stderr, "Failed to verify membership in domain!\n");
1455 /* create the dNSHostName & servicePrincipalName values */
1457 status = net_set_machine_spn( ctx, ads );
1458 if ( !ADS_ERR_OK(status) ) {
1460 d_fprintf(stderr, "Failed to set servicePrincipalNames. Please ensure that\n");
1461 d_fprintf(stderr, "the DNS domain of this server matches the AD domain,\n");
1462 d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n");
1464 /* Disable the machine account in AD. Better to fail than to leave
1465 a confused admin. */
1467 if ( net_ads_leave( 0, NULL ) != 0 ) {
1468 d_fprintf( stderr, "Failed to disable machine account in AD. Please do so manually.\n");
1471 /* clear out the machine password */
1473 netdom_store_machine_account( lp_workgroup(), domain_sid, "" );
1474 netdom_store_machine_account( short_domain_name, domain_sid, "" );
1476 nt_status = ads_ntstatus(status);
1480 if ( !net_derive_salting_principal( ctx, ads ) ) {
1481 DEBUG(1,("Failed to determine salting principal\n"));
1488 /* default to using the short UPN name */
1489 if ( !machineupn ) {
1490 snprintf( upn, sizeof(upn), "host/%s@%s", global_myname(),
1491 ads->config.realm );
1495 status = net_set_machine_upn( ctx, ads, machineupn );
1496 if ( !ADS_ERR_OK(status) ) {
1497 d_fprintf(stderr, "Failed to set userPrincipalName. Are you a Domain Admin?\n");
1501 /* Now build the keytab, using the same ADS connection */
1502 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
1503 DEBUG(1,("Error creating host keytab!\n"));
1506 #if defined(WITH_DNS_UPDATES)
1507 /* We enter this block with user creds */
1508 ads_kdestroy( NULL );
1512 if ( (ads = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1513 /* kinit with the machine password */
1515 use_in_memory_ccache();
1516 asprintf( &ads->auth.user_name, "%s$", global_myname() );
1517 ads->auth.password = secrets_fetch_machine_password(
1518 lp_workgroup(), NULL, NULL );
1519 ads->auth.realm = SMB_STRDUP( lp_realm() );
1520 ads_kinit_password( ads );
1523 if ( !ads || !NT_STATUS_IS_OK(net_update_dns( ctx, ads )) ) {
1524 d_fprintf( stderr, "DNS update failed!\n" );
1527 /* exit from this block using machine creds */
1530 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->server.realm);
1532 SAFE_FREE(machine_account);
1539 /* issue an overall failure message at the end. */
1540 d_printf("Failed to join domain: %s\n", get_friendly_nt_error_msg(nt_status));
1542 SAFE_FREE(machine_account);
1550 /*******************************************************************
1551 ********************************************************************/
1553 static int net_ads_dns_usage(int argc, const char **argv)
1555 #if defined(WITH_DNS_UPDATES)
1556 d_printf("net ads dns <command>\n");
1557 d_printf("Valid commands:\n");
1558 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1562 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1567 /*******************************************************************
1568 ********************************************************************/
1570 static int net_ads_dns_register(int argc, const char **argv)
1572 #if defined(WITH_DNS_UPDATES)
1578 struct in_addr *iplist = NULL;
1581 talloc_enable_leak_report();
1585 d_fprintf(stderr, "net ads dns register <name> <ip>\n");
1589 if (!(ctx = talloc_init("net_ads_dns"))) {
1590 d_fprintf(stderr, "Could not initialise talloc context\n");
1595 fstrcpy(name, argv[0]);
1597 name_to_fqdn(name, global_myname());
1602 if (!(iplist = SMB_MALLOC_ARRAY(struct in_addr, 1))) {
1603 d_fprintf(stderr, "net_ads_dns_register: malloc "
1607 if (inet_aton(argv[1], iplist) == 0) {
1608 d_fprintf(stderr, "net_ads_dns_register: %s is not "
1609 "a valid IP address\n", argv[1]);
1615 num_addrs = get_my_ip_address( &iplist );
1616 if ( num_addrs <= 0 ) {
1617 d_fprintf(stderr, "net_ads_dns_regiser: Failed to "
1618 "find my non-loopback IP addresses!\n");
1623 status = ads_startup_nobind(True, &ads);
1624 if ( !ADS_ERR_OK(status) ) {
1625 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1630 if ( !NT_STATUS_IS_OK(net_update_dns_internal(ctx, ads, name,
1631 iplist, num_addrs)) ) {
1632 d_fprintf( stderr, "DNS update failed!\n" );
1633 ads_destroy( &ads );
1639 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1647 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1652 #if defined(WITH_DNS_UPDATES)
1653 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1656 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1658 #if defined(WITH_DNS_UPDATES)
1662 talloc_enable_leak_report();
1666 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1671 err = do_gethostbyname(argv[0], argv[1]);
1673 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1678 static int net_ads_dns(int argc, const char *argv[])
1680 struct functable func[] = {
1681 {"REGISTER", net_ads_dns_register},
1682 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1686 return net_run_function(argc, argv, func, net_ads_dns_usage);
1689 /*******************************************************************
1690 ********************************************************************/
1692 int net_ads_printer_usage(int argc, const char **argv)
1695 "\nnet ads printer search <printer>"
1696 "\n\tsearch for a printer in the directory\n"
1697 "\nnet ads printer info <printer> <server>"
1698 "\n\tlookup info in directory for printer on server"
1699 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1700 "\nnet ads printer publish <printername>"
1701 "\n\tpublish printer in directory"
1702 "\n\t(note: printer name is required)\n"
1703 "\nnet ads printer remove <printername>"
1704 "\n\tremove printer from directory"
1705 "\n\t(note: printer name is required)\n");
1709 /*******************************************************************
1710 ********************************************************************/
1712 static int net_ads_printer_search(int argc, const char **argv)
1716 LDAPMessage *res = NULL;
1718 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1722 rc = ads_find_printers(ads, &res);
1724 if (!ADS_ERR_OK(rc)) {
1725 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1726 ads_msgfree(ads, res);
1731 if (ads_count_replies(ads, res) == 0) {
1732 d_fprintf(stderr, "No results found\n");
1733 ads_msgfree(ads, res);
1739 ads_msgfree(ads, res);
1744 static int net_ads_printer_info(int argc, const char **argv)
1748 const char *servername, *printername;
1749 LDAPMessage *res = NULL;
1751 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1756 printername = argv[0];
1762 servername = argv[1];
1764 servername = global_myname();
1767 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1769 if (!ADS_ERR_OK(rc)) {
1770 d_fprintf(stderr, "Server '%s' not found: %s\n",
1771 servername, ads_errstr(rc));
1772 ads_msgfree(ads, res);
1777 if (ads_count_replies(ads, res) == 0) {
1778 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1779 ads_msgfree(ads, res);
1785 ads_msgfree(ads, res);
1791 void do_drv_upgrade_printer(int msg_type, struct process_id src,
1792 void *buf, size_t len)
1797 static int net_ads_printer_publish(int argc, const char **argv)
1801 const char *servername, *printername;
1802 struct cli_state *cli;
1803 struct rpc_pipe_client *pipe_hnd;
1804 struct in_addr server_ip;
1806 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1807 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1808 char *prt_dn, *srv_dn, **srv_cn;
1809 LDAPMessage *res = NULL;
1811 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1816 return net_ads_printer_usage(argc, argv);
1819 printername = argv[0];
1822 servername = argv[1];
1824 servername = global_myname();
1827 /* Get printer data from SPOOLSS */
1829 resolve_name(servername, &server_ip, 0x20);
1831 nt_status = cli_full_connection(&cli, global_myname(), servername,
1834 opt_user_name, opt_workgroup,
1835 opt_password ? opt_password : "",
1836 CLI_FULL_CONNECTION_USE_KERBEROS,
1839 if (NT_STATUS_IS_ERR(nt_status)) {
1840 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1841 "for %s\n", servername, printername);
1846 /* Publish on AD server */
1848 ads_find_machine_acct(ads, &res, servername);
1850 if (ads_count_replies(ads, res) == 0) {
1851 d_fprintf(stderr, "Could not find machine account for server %s\n",
1857 srv_dn = ldap_get_dn((LDAP *)ads->ld, (LDAPMessage *)res);
1858 srv_cn = ldap_explode_dn(srv_dn, 1);
1860 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
1862 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1864 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1870 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1876 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1877 if (!ADS_ERR_OK(rc)) {
1878 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1883 d_printf("published printer\n");
1889 static int net_ads_printer_remove(int argc, const char **argv)
1893 const char *servername;
1895 LDAPMessage *res = NULL;
1897 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1902 return net_ads_printer_usage(argc, argv);
1906 servername = argv[1];
1908 servername = global_myname();
1911 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1913 if (!ADS_ERR_OK(rc)) {
1914 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1915 ads_msgfree(ads, res);
1920 if (ads_count_replies(ads, res) == 0) {
1921 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1922 ads_msgfree(ads, res);
1927 prt_dn = ads_get_dn(ads, res);
1928 ads_msgfree(ads, res);
1929 rc = ads_del_dn(ads, prt_dn);
1930 ads_memfree(ads, prt_dn);
1932 if (!ADS_ERR_OK(rc)) {
1933 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1942 static int net_ads_printer(int argc, const char **argv)
1944 struct functable func[] = {
1945 {"SEARCH", net_ads_printer_search},
1946 {"INFO", net_ads_printer_info},
1947 {"PUBLISH", net_ads_printer_publish},
1948 {"REMOVE", net_ads_printer_remove},
1952 return net_run_function(argc, argv, func, net_ads_printer_usage);
1956 static int net_ads_password(int argc, const char **argv)
1959 const char *auth_principal = opt_user_name;
1960 const char *auth_password = opt_password;
1962 char *new_password = NULL;
1967 if (opt_user_name == NULL || opt_password == NULL) {
1968 d_fprintf(stderr, "You must supply an administrator username/password\n");
1973 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1978 if (!strchr_m(user, '@')) {
1979 asprintf(&c, "%s@%s", argv[0], lp_realm());
1983 use_in_memory_ccache();
1984 c = strchr_m(auth_principal, '@');
1991 /* use the realm so we can eventually change passwords for users
1992 in realms other than default */
1993 if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
1997 /* we don't actually need a full connect, but it's the easy way to
1998 fill in the KDC's addresss */
2001 if (!ads || !ads->config.realm) {
2002 d_fprintf(stderr, "Didn't find the kerberos server!\n");
2007 new_password = (char *)argv[1];
2009 asprintf(&prompt, "Enter new password for %s:", user);
2010 new_password = getpass(prompt);
2014 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2015 auth_password, user, new_password, ads->auth.time_offset);
2016 if (!ADS_ERR_OK(ret)) {
2017 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
2022 d_printf("Password change for %s completed.\n", user);
2028 int net_ads_changetrustpw(int argc, const char **argv)
2031 char *host_principal;
2035 if (!secrets_init()) {
2036 DEBUG(1,("Failed to initialise secrets database\n"));
2040 net_use_machine_password();
2042 use_in_memory_ccache();
2044 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2048 fstrcpy(my_name, global_myname());
2049 strlower_m(my_name);
2050 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
2051 d_printf("Changing password for principal: %s\n", host_principal);
2053 ret = ads_change_trust_account_password(ads, host_principal);
2055 if (!ADS_ERR_OK(ret)) {
2056 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
2058 SAFE_FREE(host_principal);
2062 d_printf("Password change for principal %s succeeded.\n", host_principal);
2064 if (lp_use_kerberos_keytab()) {
2065 d_printf("Attempting to update system keytab with new password.\n");
2066 if (ads_keytab_create_default(ads)) {
2067 d_printf("Failed to update system keytab.\n");
2072 SAFE_FREE(host_principal);
2078 help for net ads search
2080 static int net_ads_search_usage(int argc, const char **argv)
2083 "\nnet ads search <expression> <attributes...>\n"\
2084 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2085 "The expression is a standard LDAP search expression, and the\n"\
2086 "attributes are a list of LDAP fields to show in the results\n\n"\
2087 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2089 net_common_flags_usage(argc, argv);
2095 general ADS search function. Useful in diagnosing problems in ADS
2097 static int net_ads_search(int argc, const char **argv)
2101 const char *ldap_exp;
2103 LDAPMessage *res = NULL;
2106 return net_ads_search_usage(argc, argv);
2109 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2116 rc = ads_do_search_all(ads, ads->config.bind_path,
2118 ldap_exp, attrs, &res);
2119 if (!ADS_ERR_OK(rc)) {
2120 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2125 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2127 /* dump the results */
2130 ads_msgfree(ads, res);
2138 help for net ads search
2140 static int net_ads_dn_usage(int argc, const char **argv)
2143 "\nnet ads dn <dn> <attributes...>\n"\
2144 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2145 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
2146 "to show in the results\n\n"\
2147 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2149 net_common_flags_usage(argc, argv);
2155 general ADS search function. Useful in diagnosing problems in ADS
2157 static int net_ads_dn(int argc, const char **argv)
2163 LDAPMessage *res = NULL;
2166 return net_ads_dn_usage(argc, argv);
2169 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2176 rc = ads_do_search_all(ads, dn,
2178 "(objectclass=*)", attrs, &res);
2179 if (!ADS_ERR_OK(rc)) {
2180 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2185 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2187 /* dump the results */
2190 ads_msgfree(ads, res);
2197 help for net ads sid search
2199 static int net_ads_sid_usage(int argc, const char **argv)
2202 "\nnet ads sid <sid> <attributes...>\n"\
2203 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2204 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
2205 "to show in the results\n\n"\
2206 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2208 net_common_flags_usage(argc, argv);
2214 general ADS search function. Useful in diagnosing problems in ADS
2216 static int net_ads_sid(int argc, const char **argv)
2220 const char *sid_string;
2222 LDAPMessage *res = NULL;
2226 return net_ads_sid_usage(argc, argv);
2229 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2233 sid_string = argv[0];
2236 if (!string_to_sid(&sid, sid_string)) {
2237 d_fprintf(stderr, "could not convert sid\n");
2242 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2243 if (!ADS_ERR_OK(rc)) {
2244 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2249 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2251 /* dump the results */
2254 ads_msgfree(ads, res);
2261 static int net_ads_keytab_usage(int argc, const char **argv)
2264 "net ads keytab <COMMAND>\n"\
2265 "<COMMAND> can be either:\n"\
2266 " CREATE Creates a fresh keytab\n"\
2267 " ADD Adds new service principal\n"\
2268 " FLUSH Flushes out all keytab entries\n"\
2269 " HELP Prints this help message\n"\
2270 "The ADD command will take arguments, the other commands\n"\
2271 "will not take any arguments. The arguments given to ADD\n"\
2272 "should be a list of principals to add. For example, \n"\
2273 " net ads keytab add srv1 srv2\n"\
2274 "will add principals for the services srv1 and srv2 to the\n"\
2275 "system's keytab.\n"\
2281 static int net_ads_keytab_flush(int argc, const char **argv)
2286 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2289 ret = ads_keytab_flush(ads);
2294 static int net_ads_keytab_add(int argc, const char **argv)
2300 d_printf("Processing principals to add...\n");
2301 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2304 for (i = 0; i < argc; i++) {
2305 ret |= ads_keytab_add_entry(ads, argv[i]);
2311 static int net_ads_keytab_create(int argc, const char **argv)
2316 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2319 ret = ads_keytab_create_default(ads);
2324 int net_ads_keytab(int argc, const char **argv)
2326 struct functable func[] = {
2327 {"CREATE", net_ads_keytab_create},
2328 {"ADD", net_ads_keytab_add},
2329 {"FLUSH", net_ads_keytab_flush},
2330 {"HELP", net_ads_keytab_usage},
2334 if (!lp_use_kerberos_keytab()) {
2335 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2336 use keytab functions.\n");
2339 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2342 int net_ads_help(int argc, const char **argv)
2344 struct functable func[] = {
2345 {"USER", net_ads_user_usage},
2346 {"GROUP", net_ads_group_usage},
2347 {"PRINTER", net_ads_printer_usage},
2348 {"SEARCH", net_ads_search_usage},
2349 {"INFO", net_ads_info},
2350 {"JOIN", net_ads_join_usage},
2351 {"DNS", net_ads_dns_usage},
2352 {"LEAVE", net_ads_leave},
2353 {"STATUS", net_ads_status},
2354 {"PASSWORD", net_ads_password},
2355 {"CHANGETRUSTPW", net_ads_changetrustpw},
2359 return net_run_function(argc, argv, func, net_ads_usage);
2362 int net_ads(int argc, const char **argv)
2364 struct functable func[] = {
2365 {"INFO", net_ads_info},
2366 {"JOIN", net_ads_join},
2367 {"TESTJOIN", net_ads_testjoin},
2368 {"LEAVE", net_ads_leave},
2369 {"STATUS", net_ads_status},
2370 {"USER", net_ads_user},
2371 {"GROUP", net_ads_group},
2372 {"DNS", net_ads_dns},
2373 {"PASSWORD", net_ads_password},
2374 {"CHANGETRUSTPW", net_ads_changetrustpw},
2375 {"PRINTER", net_ads_printer},
2376 {"SEARCH", net_ads_search},
2378 {"SID", net_ads_sid},
2379 {"WORKGROUP", net_ads_workgroup},
2380 {"LOOKUP", net_ads_lookup},
2381 {"KEYTAB", net_ads_keytab},
2382 {"GPO", net_ads_gpo},
2383 {"HELP", net_ads_help},
2387 return net_run_function(argc, argv, func, net_ads_usage);
2392 static int net_ads_noads(void)
2394 d_fprintf(stderr, "ADS support not compiled in\n");
2398 int net_ads_keytab(int argc, const char **argv)
2400 return net_ads_noads();
2403 int net_ads_usage(int argc, const char **argv)
2405 return net_ads_noads();
2408 int net_ads_help(int argc, const char **argv)
2410 return net_ads_noads();
2413 int net_ads_changetrustpw(int argc, const char **argv)
2415 return net_ads_noads();
2418 int net_ads_join(int argc, const char **argv)
2420 return net_ads_noads();
2423 int net_ads_user(int argc, const char **argv)
2425 return net_ads_noads();
2428 int net_ads_group(int argc, const char **argv)
2430 return net_ads_noads();
2433 /* this one shouldn't display a message */
2434 int net_ads_check(void)
2439 int net_ads_check_our_domain(void)
2444 int net_ads(int argc, const char **argv)
2446 return net_ads_usage(argc, argv);
2449 #endif /* WITH_ADS */