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;
450 if (argc < 1) return net_ads_user_usage(argc, argv);
452 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
456 status = ads_find_user_acct(ads, &res, argv[0]);
458 if (!ADS_ERR_OK(status)) {
459 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
463 if (ads_count_replies(ads, res)) {
464 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
468 if (opt_container == NULL) {
469 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
472 status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);
474 if (!ADS_ERR_OK(status)) {
475 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
480 /* if no password is to be set, we're done */
482 d_printf("User %s added\n", argv[0]);
487 /* try setting the password */
488 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
489 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
490 ads->auth.time_offset);
492 if (ADS_ERR_OK(status)) {
493 d_printf("User %s added\n", argv[0]);
498 /* password didn't set, delete account */
499 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
500 argv[0], ads_errstr(status));
501 ads_msgfree(ads, res);
502 status=ads_find_user_acct(ads, &res, argv[0]);
503 if (ADS_ERR_OK(status)) {
504 userdn = ads_get_dn(ads, res);
505 ads_del_dn(ads, userdn);
506 ads_memfree(ads, userdn);
511 ads_msgfree(ads, res);
516 static int ads_user_info(int argc, const char **argv)
521 const char *attrs[] = {"memberOf", NULL};
522 char *searchstring=NULL;
527 return net_ads_user_usage(argc, argv);
530 escaped_user = escape_ldap_string_alloc(argv[0]);
533 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
537 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
538 SAFE_FREE(escaped_user);
542 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
543 rc = ads_search(ads, &res, searchstring, attrs);
544 safe_free(searchstring);
546 if (!ADS_ERR_OK(rc)) {
547 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
549 SAFE_FREE(escaped_user);
553 grouplist = ldap_get_values((LDAP *)ads->ld,
554 (LDAPMessage *)res, "memberOf");
559 for (i=0;grouplist[i];i++) {
560 groupname = ldap_explode_dn(grouplist[i], 1);
561 d_printf("%s\n", groupname[0]);
562 ldap_value_free(groupname);
564 ldap_value_free(grouplist);
567 ads_msgfree(ads, res);
569 SAFE_FREE(escaped_user);
573 static int ads_user_delete(int argc, const char **argv)
577 LDAPMessage *res = NULL;
581 return net_ads_user_usage(argc, argv);
584 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
588 rc = ads_find_user_acct(ads, &res, argv[0]);
589 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
590 d_printf("User %s does not exist.\n", argv[0]);
591 ads_msgfree(ads, res);
595 userdn = ads_get_dn(ads, res);
596 ads_msgfree(ads, res);
597 rc = ads_del_dn(ads, userdn);
598 ads_memfree(ads, userdn);
599 if (ADS_ERR_OK(rc)) {
600 d_printf("User %s deleted\n", argv[0]);
604 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
610 int net_ads_user(int argc, const char **argv)
612 struct functable func[] = {
613 {"ADD", ads_user_add},
614 {"INFO", ads_user_info},
615 {"DELETE", ads_user_delete},
620 const char *shortattrs[] = {"sAMAccountName", NULL};
621 const char *longattrs[] = {"sAMAccountName", "description", NULL};
622 char *disp_fields[2] = {NULL, NULL};
625 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
629 if (opt_long_list_entries)
630 d_printf("\nUser name Comment"\
631 "\n-----------------------------\n");
633 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
635 "(objectCategory=user)",
636 opt_long_list_entries ? longattrs :
637 shortattrs, usergrp_display,
640 return ADS_ERR_OK(rc) ? 0 : -1;
643 return net_run_function(argc, argv, func, net_ads_user_usage);
646 static int net_ads_group_usage(int argc, const char **argv)
648 return net_help_group(argc, argv);
651 static int ads_group_add(int argc, const char **argv)
655 LDAPMessage *res=NULL;
659 return net_ads_group_usage(argc, argv);
662 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
666 status = ads_find_user_acct(ads, &res, argv[0]);
668 if (!ADS_ERR_OK(status)) {
669 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
673 if (ads_count_replies(ads, res)) {
674 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
678 if (opt_container == NULL) {
679 opt_container = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
682 status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);
684 if (ADS_ERR_OK(status)) {
685 d_printf("Group %s added\n", argv[0]);
688 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
694 ads_msgfree(ads, res);
699 static int ads_group_delete(int argc, const char **argv)
703 LDAPMessage *res = NULL;
707 return net_ads_group_usage(argc, argv);
710 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
714 rc = ads_find_user_acct(ads, &res, argv[0]);
715 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
716 d_printf("Group %s does not exist.\n", argv[0]);
717 ads_msgfree(ads, res);
721 groupdn = ads_get_dn(ads, res);
722 ads_msgfree(ads, res);
723 rc = ads_del_dn(ads, groupdn);
724 ads_memfree(ads, groupdn);
725 if (ADS_ERR_OK(rc)) {
726 d_printf("Group %s deleted\n", argv[0]);
730 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
736 int net_ads_group(int argc, const char **argv)
738 struct functable func[] = {
739 {"ADD", ads_group_add},
740 {"DELETE", ads_group_delete},
745 const char *shortattrs[] = {"sAMAccountName", NULL};
746 const char *longattrs[] = {"sAMAccountName", "description", NULL};
747 char *disp_fields[2] = {NULL, NULL};
750 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
754 if (opt_long_list_entries)
755 d_printf("\nGroup name Comment"\
756 "\n-----------------------------\n");
757 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
759 "(objectCategory=group)",
760 opt_long_list_entries ? longattrs :
761 shortattrs, usergrp_display,
765 return ADS_ERR_OK(rc) ? 0 : -1;
767 return net_run_function(argc, argv, func, net_ads_group_usage);
770 static int net_ads_status(int argc, const char **argv)
776 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
780 rc = ads_find_machine_acct(ads, &res, global_myname());
781 if (!ADS_ERR_OK(rc)) {
782 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
787 if (ads_count_replies(ads, res) == 0) {
788 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
798 /*******************************************************************
799 Leave an AD domain. Windows XP disables the machine account.
800 We'll try the same. The old code would do an LDAP delete.
801 That only worked using the machine creds because added the machine
802 with full control to the computer object's ACL.
803 *******************************************************************/
805 static int net_ads_leave(int argc, const char **argv)
807 ADS_STRUCT *ads = NULL;
811 struct cli_state *cli = NULL;
813 DOM_SID *dom_sid = NULL;
815 if (!secrets_init()) {
816 DEBUG(1,("Failed to initialise secrets database\n"));
820 if (!(ctx = talloc_init("net_ads_leave"))) {
821 d_fprintf(stderr, "Could not initialise talloc context.\n");
825 /* The finds a DC and takes care of getting the
826 user creds if necessary */
828 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
832 /* make RPC calls here */
834 if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, &ads->ldap_ip,
835 ads->config.ldap_server_name)) )
840 saf_store( cli->server_domain, cli->desthost );
842 if ( !NT_STATUS_IS_OK(netdom_get_domain_sid( ctx, cli, &dom_sid )) ) {
846 status = netdom_leave_domain(ctx, cli, dom_sid);
848 /* Ty and delete it via LDAP - the old way we used to. */
850 adsret = ads_leave_realm(ads, global_myname());
851 if (ADS_ERR_OK(adsret)) {
852 d_printf("Deleted account for '%s' in realm '%s'\n",
853 global_myname(), ads->config.realm);
856 /* We couldn't delete it - see if the disable succeeded. */
857 if (NT_STATUS_IS_OK(status)) {
858 d_printf("Disabled account for '%s' in realm '%s'\n",
859 global_myname(), ads->config.realm);
862 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
863 global_myname(), ads->config.realm);
878 static NTSTATUS net_ads_join_ok(void)
880 ADS_STRUCT *ads = NULL;
883 if (!secrets_init()) {
884 DEBUG(1,("Failed to initialise secrets database\n"));
885 return NT_STATUS_ACCESS_DENIED;
888 net_use_machine_password();
890 status = ads_startup(True, &ads);
891 if (!ADS_ERR_OK(status)) {
892 return ads_ntstatus(status);
900 check that an existing join is OK
902 int net_ads_testjoin(int argc, const char **argv)
905 use_in_memory_ccache();
907 /* Display success or failure */
908 status = net_ads_join_ok();
909 if (!NT_STATUS_IS_OK(status)) {
910 fprintf(stderr,"Join to domain is not valid: %s\n",
911 get_friendly_nt_error_msg(status));
915 printf("Join is OK\n");
919 /*******************************************************************
920 Simple configu checks before beginning the join
921 ********************************************************************/
923 static NTSTATUS check_ads_config( void )
925 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
926 d_printf("Host is not configured as a member server.\n");
927 return NT_STATUS_INVALID_DOMAIN_ROLE;
930 if (strlen(global_myname()) > 15) {
931 d_printf("Our netbios name can be at most 15 chars long, "
932 "\"%s\" is %u chars long\n", global_myname(),
933 (unsigned int)strlen(global_myname()));
934 return NT_STATUS_NAME_TOO_LONG;
937 if ( lp_security() == SEC_ADS && !*lp_realm()) {
938 d_fprintf(stderr, "realm must be set in in smb.conf for ADS "
939 "join to succeed.\n");
940 return NT_STATUS_INVALID_PARAMETER;
943 if (!secrets_init()) {
944 DEBUG(1,("Failed to initialise secrets database\n"));
945 /* This is a good bet for failure of secrets_init ... */
946 return NT_STATUS_ACCESS_DENIED;
952 /*******************************************************************
954 ********************************************************************/
956 static NTSTATUS net_join_domain(TALLOC_CTX *ctx, const char *servername,
957 struct in_addr *ip, DOM_SID **dom_sid,
958 const char *password)
960 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
961 struct cli_state *cli = NULL;
963 ret = connect_to_ipc_krb5(&cli, ip, servername);
964 if ( !NT_STATUS_IS_OK(ret) ) {
968 saf_store( cli->server_domain, cli->desthost );
970 ret = netdom_get_domain_sid( ctx, cli, dom_sid );
971 if ( !NT_STATUS_IS_OK(ret) ) {
975 ret = netdom_join_domain( ctx, cli, *dom_sid, password, ND_TYPE_AD );
984 /*******************************************************************
985 Set a machines dNSHostName and servicePrincipalName attributes
986 ********************************************************************/
988 static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
990 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
993 const char *servicePrincipalName[3] = {NULL, NULL, NULL};
996 LDAPMessage *res = NULL;
997 char *dn_string = NULL;
998 const char *machine_name = global_myname();
1001 if ( !machine_name ) {
1002 return ADS_ERROR(LDAP_NO_MEMORY);
1007 status = ads_find_machine_acct(ads_s, &res, machine_name);
1008 if (!ADS_ERR_OK(status))
1011 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1012 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1013 return ADS_ERROR(LDAP_NO_MEMORY);
1016 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1017 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1021 new_dn = talloc_strdup(ctx, dn_string);
1022 ads_memfree(ads_s, dn_string);
1024 return ADS_ERROR(LDAP_NO_MEMORY);
1027 /* Windows only creates HOST/shortname & HOST/fqdn. */
1029 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) )
1032 servicePrincipalName[0] = psp;
1034 name_to_fqdn(my_fqdn, machine_name);
1035 strlower_m(my_fqdn);
1036 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) )
1038 servicePrincipalName[1] = psp;
1040 if (!(mods = ads_init_mods(ctx))) {
1044 /* fields of primary importance */
1046 ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
1047 ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
1049 status = ads_gen_mod(ads_s, new_dn, mods);
1052 ads_msgfree(ads_s, res);
1057 /*******************************************************************
1058 Set a machines dNSHostName and servicePrincipalName attributes
1059 ********************************************************************/
1061 static ADS_STATUS net_set_machine_upn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, const char *upn )
1063 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1066 LDAPMessage *res = NULL;
1067 char *dn_string = NULL;
1068 const char *machine_name = global_myname();
1071 if ( !machine_name ) {
1072 return ADS_ERROR(LDAP_NO_MEMORY);
1077 status = ads_find_machine_acct(ads_s, &res, machine_name);
1078 if (!ADS_ERR_OK(status))
1081 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1082 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1083 return ADS_ERROR(LDAP_NO_MEMORY);
1086 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1087 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1091 new_dn = talloc_strdup(ctx, dn_string);
1092 ads_memfree(ads_s, dn_string);
1094 return ADS_ERROR(LDAP_NO_MEMORY);
1097 /* now do the mods */
1099 if (!(mods = ads_init_mods(ctx))) {
1103 /* fields of primary importance */
1105 ads_mod_str(ctx, &mods, "userPrincipalName", upn);
1107 status = ads_gen_mod(ads_s, new_dn, mods);
1110 ads_msgfree(ads_s, res);
1115 /*******************************************************************
1116 join a domain using ADS (LDAP mods)
1117 ********************************************************************/
1119 static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
1121 ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
1123 LDAPMessage *res = NULL;
1125 ou_str = ads_ou_string(ads, ou);
1126 asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
1129 rc = ads_search_dn(ads, &res, dn, NULL);
1130 ads_msgfree(ads, res);
1132 if (ADS_ERR_OK(rc)) {
1133 /* Attempt to create the machine account and bail if this fails.
1134 Assume that the admin wants exactly what they requested */
1136 rc = ads_create_machine_acct( ads, global_myname(), dn );
1137 if ( rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS ) {
1147 /************************************************************************
1148 ************************************************************************/
1150 static BOOL net_derive_salting_principal( TALLOC_CTX *ctx, ADS_STRUCT *ads )
1156 LDAPMessage *res = NULL;
1157 const char *machine_name = global_myname();
1159 status = ads_domain_func_level( ads, &domain_func );
1160 if ( !ADS_ERR_OK(status) ) {
1161 DEBUG(2,("Failed to determine domain functional level!\n"));
1165 /* go ahead and setup the default salt */
1167 if ( (std_salt = kerberos_standard_des_salt()) == NULL ) {
1168 d_fprintf(stderr, "net_derive_salting_principal: failed to obtain stanard DES salt\n");
1172 fstrcpy( salt, std_salt );
1173 SAFE_FREE( std_salt );
1175 /* if it's a Windows functional domain, we have to look for the UPN */
1177 if ( domain_func == DS_DOMAIN_FUNCTION_2000 ) {
1181 status = ads_find_machine_acct(ads, &res, machine_name);
1182 if (!ADS_ERR_OK(status)) {
1186 if ( (count = ads_count_replies(ads, res)) != 1 ) {
1187 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1191 upn = ads_pull_string(ads, ctx, res, "userPrincipalName");
1193 fstrcpy( salt, upn );
1196 ads_msgfree(ads, res);
1199 return kerberos_secrets_store_des_salt( salt );
1202 /*******************************************************************
1203 Send a DNS update request
1204 *******************************************************************/
1206 #if defined(WITH_DNS_UPDATES)
1207 static BOOL net_update_dns( TALLOC_CTX *ctx, ADS_STRUCT *ads )
1210 struct in_addr *iplist = NULL;
1211 struct dns_rr_ns *nameservers = NULL;
1214 NTSTATUS dns_status;
1215 fstring machine_name;
1217 const char *dnsdomain;
1218 ADS_STRUCT *ads_s = NULL;
1220 name_to_fqdn( machine_name, global_myname() );
1221 strlower_m( machine_name );
1223 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1224 d_printf("No DNS domain configured for %s. Unable to perform DNS Update.\n",
1230 dns_status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1231 if ( !NT_STATUS_IS_OK(dns_status) || (ns_count == 0)) {
1232 DEBUG(3,("net_ads_join: Failed to find name server for the %s realm\n",
1233 ads->config.realm));
1237 /* Get our ip address (not the 127.0.0.x address but a real ip address) */
1239 num_addrs = get_my_ip_address( &iplist );
1240 if ( num_addrs <= 0 ) {
1241 DEBUG(4,("net_ads_join: Failed to find my non-loopback IP addresses!\n"));
1246 /* Drop the user creds */
1248 ads_kdestroy( NULL );
1250 ads_s = ads_init( ads->server.realm, ads->server.workgroup, ads->server.ldap_server );
1252 DEBUG(1,("net_ads_join: ads_init() failed!\n"));
1257 /* kinit with the machine password */
1259 asprintf( &ads_s->auth.user_name, "%s$", global_myname() );
1260 ads_s->auth.password = secrets_fetch_machine_password( lp_workgroup(), NULL, NULL );
1261 ads_s->auth.realm = SMB_STRDUP( lp_realm() );
1262 ads_kinit_password( ads_s );
1264 /* Now perform the dns update - we'll try non-secure and if we fail, we'll
1265 follow it up with a secure update */
1267 fstrcpy( dns_server, nameservers[0].hostname );
1269 ret = DoDNSUpdate(dns_server, dnsdomain, machine_name, iplist, num_addrs );
1271 DEBUG(1, ("Error creating dns update!\n"));
1275 SAFE_FREE( iplist );
1277 ads_destroy( &ads_s );
1284 /*******************************************************************
1285 utility function to parse an integer parameter from
1287 **********************************************************/
1288 static char* get_string_param( const char* param )
1292 if ( (p = strchr( param, '=' )) == NULL )
1298 /*******************************************************************
1299 ********************************************************************/
1301 static int net_ads_join_usage(int argc, const char **argv)
1303 d_printf("net ads join [options]\n");
1304 d_printf("Valid options:\n");
1305 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1306 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1307 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1308 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1309 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1314 /*******************************************************************
1315 ********************************************************************/
1317 int net_ads_join(int argc, const char **argv)
1319 ADS_STRUCT *ads = NULL;
1322 char *machine_account = NULL;
1323 const char *short_domain_name = NULL;
1324 char *tmp_password, *password;
1325 struct cldap_netlogon_reply cldap_reply;
1326 TALLOC_CTX *ctx = NULL;
1327 DOM_SID *domain_sid = NULL;
1328 BOOL createupn = False;
1329 const char *machineupn = NULL;
1330 const char *create_in_ou = NULL;
1333 nt_status = check_ads_config();
1334 if (!NT_STATUS_IS_OK(nt_status)) {
1335 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1339 status = ads_startup(True, &ads);
1340 if (!ADS_ERR_OK(status)) {
1341 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1342 nt_status = ads_ntstatus(status);
1346 if (strcmp(ads->config.realm, lp_realm()) != 0) {
1347 d_fprintf(stderr, "realm of remote server (%s) and realm in smb.conf "
1348 "(%s) DO NOT match. Aborting join\n", ads->config.realm,
1350 nt_status = NT_STATUS_INVALID_PARAMETER;
1354 if (!(ctx = talloc_init("net_ads_join"))) {
1355 d_fprintf(stderr, "Could not initialise talloc context.\n");
1356 nt_status = NT_STATUS_NO_MEMORY;
1360 /* process additional command line args */
1362 for ( i=0; i<argc; i++ ) {
1363 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1365 machineupn = get_string_param(argv[i]);
1367 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1368 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1369 d_fprintf(stderr, "Please supply a valid OU path\n");
1370 nt_status = NT_STATUS_INVALID_PARAMETER;
1375 d_fprintf(stderr, "Bad option: %s\n", argv[i]);
1376 nt_status = NT_STATUS_INVALID_PARAMETER;
1381 /* If we were given an OU, try to create the machine in
1382 the OU account first and then do the normal RPC join */
1384 if ( create_in_ou ) {
1385 status = net_precreate_machine_acct( ads, create_in_ou );
1386 if ( !ADS_ERR_OK(status) ) {
1387 d_fprintf( stderr, "Failed to pre-create the machine object "
1388 "in OU %s.\n", argv[0]);
1389 DEBUG(1, ("error calling net_precreate_machine_acct: %s\n",
1390 ads_errstr(status)));
1391 nt_status = ads_ntstatus(status);
1396 /* Do the domain join here */
1398 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1399 password = talloc_strdup(ctx, tmp_password);
1401 nt_status = net_join_domain(ctx, ads->config.ldap_server_name,
1402 &ads->ldap_ip, &domain_sid, password);
1403 if ( !NT_STATUS_IS_OK(nt_status) ) {
1404 DEBUG(1, ("call of net_join_domain failed: %s\n",
1405 get_friendly_nt_error_msg(nt_status)));
1409 /* Check the short name of the domain */
1411 ZERO_STRUCT( cldap_reply );
1413 if ( ads_cldap_netlogon( ads->config.ldap_server_name,
1414 ads->server.realm, &cldap_reply ) )
1416 short_domain_name = talloc_strdup( ctx, cldap_reply.netbios_domain );
1417 if ( !strequal(lp_workgroup(), short_domain_name) ) {
1418 d_printf("The workgroup in smb.conf does not match the short\n");
1419 d_printf("domain name obtained from the server.\n");
1420 d_printf("Using the name [%s] from the server.\n", short_domain_name);
1421 d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
1424 short_domain_name = lp_workgroup();
1427 d_printf("Using short domain name -- %s\n", short_domain_name);
1429 /* HACK ALERT! Store the sid and password under both the lp_workgroup()
1430 value from smb.conf and the string returned from the server. The former is
1431 neede to bootstrap winbindd's first connection to the DC to get the real
1432 short domain name --jerry */
1434 if ( (netdom_store_machine_account( lp_workgroup(), domain_sid, password ) == -1)
1435 || (netdom_store_machine_account( short_domain_name, domain_sid, password ) == -1) )
1437 /* issue an internal error here for now.
1438 * everything else would mean changing tdb routines. */
1439 nt_status = NT_STATUS_INTERNAL_ERROR;
1443 /* Verify that everything is ok */
1445 if ( net_rpc_join_ok(short_domain_name, ads->config.ldap_server_name, &ads->ldap_ip) != 0 ) {
1446 d_fprintf(stderr, "Failed to verify membership in domain!\n");
1450 /* create the dNSHostName & servicePrincipalName values */
1452 status = net_set_machine_spn( ctx, ads );
1453 if ( !ADS_ERR_OK(status) ) {
1455 d_fprintf(stderr, "Failed to set servicePrincipalNames. Please ensure that\n");
1456 d_fprintf(stderr, "the DNS domain of this server matches the AD domain,\n");
1457 d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n");
1459 /* Disable the machine account in AD. Better to fail than to leave
1460 a confused admin. */
1462 if ( net_ads_leave( 0, NULL ) != 0 ) {
1463 d_fprintf( stderr, "Failed to disable machine account in AD. Please do so manually.\n");
1466 /* clear out the machine password */
1468 netdom_store_machine_account( lp_workgroup(), domain_sid, "" );
1469 netdom_store_machine_account( short_domain_name, domain_sid, "" );
1471 nt_status = ads_ntstatus(status);
1475 if ( !net_derive_salting_principal( ctx, ads ) ) {
1476 DEBUG(1,("Failed to determine salting principal\n"));
1483 /* default to using the short UPN name */
1484 if ( !machineupn ) {
1485 snprintf( upn, sizeof(upn), "host/%s@%s", global_myname(),
1486 ads->config.realm );
1490 status = net_set_machine_upn( ctx, ads, machineupn );
1491 if ( !ADS_ERR_OK(status) ) {
1492 d_fprintf(stderr, "Failed to set userPrincipalName. Are you a Domain Admin?\n");
1496 /* Now build the keytab, using the same ADS connection */
1497 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
1498 DEBUG(1,("Error creating host keytab!\n"));
1501 #if defined(WITH_DNS_UPDATES)
1502 /* We enter this block with user creds */
1504 if ( !net_update_dns( ctx, ads ) ) {
1505 d_fprintf( stderr, "DNS update failed!\n" );
1508 /* exit from this block using machine creds */
1511 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
1513 SAFE_FREE(machine_account);
1520 /* issue an overall failure message at the end. */
1521 d_printf("Failed to join domain: %s\n", get_friendly_nt_error_msg(nt_status));
1523 SAFE_FREE(machine_account);
1531 /*******************************************************************
1532 ********************************************************************/
1534 static int net_ads_dns_usage(int argc, const char **argv)
1536 #if defined(WITH_DNS_UPDATES)
1537 d_printf("net ads dns <command>\n");
1538 d_printf("Valid commands:\n");
1539 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1543 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1548 /*******************************************************************
1549 ********************************************************************/
1551 static int net_ads_dns(int argc, const char **argv)
1553 #if defined(WITH_DNS_UPDATES)
1557 BOOL register_dns = False;
1560 status = ads_startup(True, &ads);
1561 if ( !ADS_ERR_OK(status) ) {
1562 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1566 if (!(ctx = talloc_init("net_ads_dns"))) {
1567 DEBUG(0, ("Could not initialise talloc context\n"));
1571 /* process additional command line args */
1573 for ( i=0; i<argc; i++ ) {
1574 if ( strequal(argv[i], "register") ) {
1575 register_dns = True;
1578 d_fprintf(stderr, "Bad option: %s\n", argv[i]);
1583 if ( !net_update_dns( ctx, ads ) ) {
1584 d_fprintf( stderr, "DNS update failed!\n" );
1585 ads_destroy( &ads );
1590 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1597 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1602 /*******************************************************************
1603 ********************************************************************/
1605 int net_ads_printer_usage(int argc, const char **argv)
1608 "\nnet ads printer search <printer>"
1609 "\n\tsearch for a printer in the directory\n"
1610 "\nnet ads printer info <printer> <server>"
1611 "\n\tlookup info in directory for printer on server"
1612 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1613 "\nnet ads printer publish <printername>"
1614 "\n\tpublish printer in directory"
1615 "\n\t(note: printer name is required)\n"
1616 "\nnet ads printer remove <printername>"
1617 "\n\tremove printer from directory"
1618 "\n\t(note: printer name is required)\n");
1622 /*******************************************************************
1623 ********************************************************************/
1625 static int net_ads_printer_search(int argc, const char **argv)
1629 LDAPMessage *res = NULL;
1631 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1635 rc = ads_find_printers(ads, &res);
1637 if (!ADS_ERR_OK(rc)) {
1638 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1639 ads_msgfree(ads, res);
1644 if (ads_count_replies(ads, res) == 0) {
1645 d_fprintf(stderr, "No results found\n");
1646 ads_msgfree(ads, res);
1652 ads_msgfree(ads, res);
1657 static int net_ads_printer_info(int argc, const char **argv)
1661 const char *servername, *printername;
1662 LDAPMessage *res = NULL;
1664 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1669 printername = argv[0];
1675 servername = argv[1];
1677 servername = global_myname();
1680 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1682 if (!ADS_ERR_OK(rc)) {
1683 d_fprintf(stderr, "Server '%s' not found: %s\n",
1684 servername, ads_errstr(rc));
1685 ads_msgfree(ads, res);
1690 if (ads_count_replies(ads, res) == 0) {
1691 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1692 ads_msgfree(ads, res);
1698 ads_msgfree(ads, res);
1704 void do_drv_upgrade_printer(int msg_type, struct process_id src,
1705 void *buf, size_t len)
1710 static int net_ads_printer_publish(int argc, const char **argv)
1714 const char *servername, *printername;
1715 struct cli_state *cli;
1716 struct rpc_pipe_client *pipe_hnd;
1717 struct in_addr server_ip;
1719 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1720 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1721 char *prt_dn, *srv_dn, **srv_cn;
1722 LDAPMessage *res = NULL;
1724 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1729 return net_ads_printer_usage(argc, argv);
1732 printername = argv[0];
1735 servername = argv[1];
1737 servername = global_myname();
1740 /* Get printer data from SPOOLSS */
1742 resolve_name(servername, &server_ip, 0x20);
1744 nt_status = cli_full_connection(&cli, global_myname(), servername,
1747 opt_user_name, opt_workgroup,
1748 opt_password ? opt_password : "",
1749 CLI_FULL_CONNECTION_USE_KERBEROS,
1752 if (NT_STATUS_IS_ERR(nt_status)) {
1753 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1754 "for %s\n", servername, printername);
1759 /* Publish on AD server */
1761 ads_find_machine_acct(ads, &res, servername);
1763 if (ads_count_replies(ads, res) == 0) {
1764 d_fprintf(stderr, "Could not find machine account for server %s\n",
1770 srv_dn = ldap_get_dn((LDAP *)ads->ld, (LDAPMessage *)res);
1771 srv_cn = ldap_explode_dn(srv_dn, 1);
1773 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn);
1775 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1777 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1783 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1789 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1790 if (!ADS_ERR_OK(rc)) {
1791 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1796 d_printf("published printer\n");
1802 static int net_ads_printer_remove(int argc, const char **argv)
1806 const char *servername;
1808 LDAPMessage *res = NULL;
1810 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1815 return net_ads_printer_usage(argc, argv);
1819 servername = argv[1];
1821 servername = global_myname();
1824 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1826 if (!ADS_ERR_OK(rc)) {
1827 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1828 ads_msgfree(ads, res);
1833 if (ads_count_replies(ads, res) == 0) {
1834 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1835 ads_msgfree(ads, res);
1840 prt_dn = ads_get_dn(ads, res);
1841 ads_msgfree(ads, res);
1842 rc = ads_del_dn(ads, prt_dn);
1843 ads_memfree(ads, prt_dn);
1845 if (!ADS_ERR_OK(rc)) {
1846 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1855 static int net_ads_printer(int argc, const char **argv)
1857 struct functable func[] = {
1858 {"SEARCH", net_ads_printer_search},
1859 {"INFO", net_ads_printer_info},
1860 {"PUBLISH", net_ads_printer_publish},
1861 {"REMOVE", net_ads_printer_remove},
1865 return net_run_function(argc, argv, func, net_ads_printer_usage);
1869 static int net_ads_password(int argc, const char **argv)
1872 const char *auth_principal = opt_user_name;
1873 const char *auth_password = opt_password;
1875 char *new_password = NULL;
1880 if (opt_user_name == NULL || opt_password == NULL) {
1881 d_fprintf(stderr, "You must supply an administrator username/password\n");
1886 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1891 if (!strchr_m(user, '@')) {
1892 asprintf(&c, "%s@%s", argv[0], lp_realm());
1896 use_in_memory_ccache();
1897 c = strchr_m(auth_principal, '@');
1904 /* use the realm so we can eventually change passwords for users
1905 in realms other than default */
1906 if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
1910 /* we don't actually need a full connect, but it's the easy way to
1911 fill in the KDC's addresss */
1914 if (!ads || !ads->config.realm) {
1915 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1920 new_password = (char *)argv[1];
1922 asprintf(&prompt, "Enter new password for %s:", user);
1923 new_password = getpass(prompt);
1927 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1928 auth_password, user, new_password, ads->auth.time_offset);
1929 if (!ADS_ERR_OK(ret)) {
1930 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1935 d_printf("Password change for %s completed.\n", user);
1941 int net_ads_changetrustpw(int argc, const char **argv)
1944 char *host_principal;
1948 if (!secrets_init()) {
1949 DEBUG(1,("Failed to initialise secrets database\n"));
1953 net_use_machine_password();
1955 use_in_memory_ccache();
1957 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1961 fstrcpy(my_name, global_myname());
1962 strlower_m(my_name);
1963 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1964 d_printf("Changing password for principal: %s\n", host_principal);
1966 ret = ads_change_trust_account_password(ads, host_principal);
1968 if (!ADS_ERR_OK(ret)) {
1969 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1971 SAFE_FREE(host_principal);
1975 d_printf("Password change for principal %s succeeded.\n", host_principal);
1977 if (lp_use_kerberos_keytab()) {
1978 d_printf("Attempting to update system keytab with new password.\n");
1979 if (ads_keytab_create_default(ads)) {
1980 d_printf("Failed to update system keytab.\n");
1985 SAFE_FREE(host_principal);
1991 help for net ads search
1993 static int net_ads_search_usage(int argc, const char **argv)
1996 "\nnet ads search <expression> <attributes...>\n"\
1997 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1998 "The expression is a standard LDAP search expression, and the\n"\
1999 "attributes are a list of LDAP fields to show in the results\n\n"\
2000 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2002 net_common_flags_usage(argc, argv);
2008 general ADS search function. Useful in diagnosing problems in ADS
2010 static int net_ads_search(int argc, const char **argv)
2014 const char *ldap_exp;
2016 LDAPMessage *res = NULL;
2019 return net_ads_search_usage(argc, argv);
2022 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2029 rc = ads_do_search_all(ads, ads->config.bind_path,
2031 ldap_exp, attrs, &res);
2032 if (!ADS_ERR_OK(rc)) {
2033 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2038 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2040 /* dump the results */
2043 ads_msgfree(ads, res);
2051 help for net ads search
2053 static int net_ads_dn_usage(int argc, const char **argv)
2056 "\nnet ads dn <dn> <attributes...>\n"\
2057 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2058 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
2059 "to show in the results\n\n"\
2060 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2062 net_common_flags_usage(argc, argv);
2068 general ADS search function. Useful in diagnosing problems in ADS
2070 static int net_ads_dn(int argc, const char **argv)
2076 LDAPMessage *res = NULL;
2079 return net_ads_dn_usage(argc, argv);
2082 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2089 rc = ads_do_search_all(ads, dn,
2091 "(objectclass=*)", attrs, &res);
2092 if (!ADS_ERR_OK(rc)) {
2093 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2098 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2100 /* dump the results */
2103 ads_msgfree(ads, res);
2110 help for net ads sid search
2112 static int net_ads_sid_usage(int argc, const char **argv)
2115 "\nnet ads sid <sid> <attributes...>\n"\
2116 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2117 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
2118 "to show in the results\n\n"\
2119 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2121 net_common_flags_usage(argc, argv);
2127 general ADS search function. Useful in diagnosing problems in ADS
2129 static int net_ads_sid(int argc, const char **argv)
2133 const char *sid_string;
2135 LDAPMessage *res = NULL;
2139 return net_ads_sid_usage(argc, argv);
2142 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2146 sid_string = argv[0];
2149 if (!string_to_sid(&sid, sid_string)) {
2150 d_fprintf(stderr, "could not convert sid\n");
2155 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2156 if (!ADS_ERR_OK(rc)) {
2157 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2162 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2164 /* dump the results */
2167 ads_msgfree(ads, res);
2174 static int net_ads_keytab_usage(int argc, const char **argv)
2177 "net ads keytab <COMMAND>\n"\
2178 "<COMMAND> can be either:\n"\
2179 " CREATE Creates a fresh keytab\n"\
2180 " ADD Adds new service principal\n"\
2181 " FLUSH Flushes out all keytab entries\n"\
2182 " HELP Prints this help message\n"\
2183 "The ADD command will take arguments, the other commands\n"\
2184 "will not take any arguments. The arguments given to ADD\n"\
2185 "should be a list of principals to add. For example, \n"\
2186 " net ads keytab add srv1 srv2\n"\
2187 "will add principals for the services srv1 and srv2 to the\n"\
2188 "system's keytab.\n"\
2194 static int net_ads_keytab_flush(int argc, const char **argv)
2199 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2202 ret = ads_keytab_flush(ads);
2207 static int net_ads_keytab_add(int argc, const char **argv)
2213 d_printf("Processing principals to add...\n");
2214 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2217 for (i = 0; i < argc; i++) {
2218 ret |= ads_keytab_add_entry(ads, argv[i]);
2224 static int net_ads_keytab_create(int argc, const char **argv)
2229 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2232 ret = ads_keytab_create_default(ads);
2237 int net_ads_keytab(int argc, const char **argv)
2239 struct functable func[] = {
2240 {"CREATE", net_ads_keytab_create},
2241 {"ADD", net_ads_keytab_add},
2242 {"FLUSH", net_ads_keytab_flush},
2243 {"HELP", net_ads_keytab_usage},
2247 if (!lp_use_kerberos_keytab()) {
2248 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2249 use keytab functions.\n");
2252 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2255 int net_ads_help(int argc, const char **argv)
2257 struct functable func[] = {
2258 {"USER", net_ads_user_usage},
2259 {"GROUP", net_ads_group_usage},
2260 {"PRINTER", net_ads_printer_usage},
2261 {"SEARCH", net_ads_search_usage},
2262 {"INFO", net_ads_info},
2263 {"JOIN", net_ads_join_usage},
2264 {"DNS", net_ads_dns_usage},
2265 {"LEAVE", net_ads_leave},
2266 {"STATUS", net_ads_status},
2267 {"PASSWORD", net_ads_password},
2268 {"CHANGETRUSTPW", net_ads_changetrustpw},
2272 return net_run_function(argc, argv, func, net_ads_usage);
2275 int net_ads(int argc, const char **argv)
2277 struct functable func[] = {
2278 {"INFO", net_ads_info},
2279 {"JOIN", net_ads_join},
2280 {"TESTJOIN", net_ads_testjoin},
2281 {"LEAVE", net_ads_leave},
2282 {"STATUS", net_ads_status},
2283 {"USER", net_ads_user},
2284 {"GROUP", net_ads_group},
2285 {"DNS", net_ads_dns},
2286 {"PASSWORD", net_ads_password},
2287 {"CHANGETRUSTPW", net_ads_changetrustpw},
2288 {"PRINTER", net_ads_printer},
2289 {"SEARCH", net_ads_search},
2291 {"SID", net_ads_sid},
2292 {"WORKGROUP", net_ads_workgroup},
2293 {"LOOKUP", net_ads_lookup},
2294 {"KEYTAB", net_ads_keytab},
2295 {"GPO", net_ads_gpo},
2296 {"HELP", net_ads_help},
2300 return net_run_function(argc, argv, func, net_ads_usage);
2305 static int net_ads_noads(void)
2307 d_fprintf(stderr, "ADS support not compiled in\n");
2311 int net_ads_keytab(int argc, const char **argv)
2313 return net_ads_noads();
2316 int net_ads_usage(int argc, const char **argv)
2318 return net_ads_noads();
2321 int net_ads_help(int argc, const char **argv)
2323 return net_ads_noads();
2326 int net_ads_changetrustpw(int argc, const char **argv)
2328 return net_ads_noads();
2331 int net_ads_join(int argc, const char **argv)
2333 return net_ads_noads();
2336 int net_ads_user(int argc, const char **argv)
2338 return net_ads_noads();
2341 int net_ads_group(int argc, const char **argv)
2343 return net_ads_noads();
2346 /* this one shouldn't display a message */
2347 int net_ads_check(void)
2352 int net_ads_check_our_domain(void)
2357 int net_ads(int argc, const char **argv)
2359 return net_ads_usage(argc, argv);
2362 #endif /* WITH_ADS */