Set the right domain\user in cli_rpc_pipe_open_ntlmssp_internal
[Samba/bb.git] / source / utils / net_ads.c
blobc8bfc2630cc8283870f92a90cf949b766f9f3784
1 /*
2 Samba Unix/Linux SMB client library
3 net ads commands
4 Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5 Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6 Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7 Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "utils/net.h"
26 #include "libnet/libnet.h"
28 #ifdef HAVE_ADS
30 int net_ads_usage(int argc, const char **argv)
32 d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
33 d_printf(" Join the local machine to a ADS realm\n");
34 d_printf("leave\n");
35 d_printf(" Remove the local machine from a ADS realm\n");
36 d_printf("testjoin\n");
37 d_printf(" Validates the machine account in the domain\n");
38 d_printf("user\n");
39 d_printf(" List, add, or delete users in the realm\n");
40 d_printf("group\n");
41 d_printf(" List, add, or delete groups in the realm\n");
42 d_printf("info\n");
43 d_printf(" Displays details regarding a specific AD server\n");
44 d_printf("status\n");
45 d_printf(" Display details regarding the machine's account in AD\n");
46 d_printf("lookup\n");
47 d_printf(" Performs CLDAP query of AD domain controllers\n");
48 d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
49 d_printf(" Change a user's password using an admin account\n");
50 d_printf(" (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
51 d_printf("changetrustpw\n");
52 d_printf(" Change the trust account password of this machine in the AD tree\n");
53 d_printf("printer [info | publish | remove] <printername> <servername>\n");
54 d_printf(" Lookup, add, or remove directory entry for a printer\n");
55 d_printf("{search,dn,sid}\n");
56 d_printf(" Issue LDAP search queries using a general filter, by DN, or by SID\n");
57 d_printf("keytab\n");
58 d_printf(" Manage a local keytab file based on the machine account in AD\n");
59 d_printf("dns\n");
60 d_printf(" Issue a dynamic DNS update request the server's hostname\n");
61 d_printf(" (using the machine credentials)\n");
63 return -1;
66 /* when we do not have sufficient input parameters to contact a remote domain
67 * we always fall back to our own realm - Guenther*/
69 static const char *assume_own_realm(void)
71 if (!opt_host && strequal(lp_workgroup(), opt_target_workgroup)) {
72 return lp_realm();
75 return NULL;
79 do a cldap netlogon query
81 static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
83 char addr[INET6_ADDRSTRLEN];
84 struct cldap_netlogon_reply reply;
85 struct GUID tmp_guid;
87 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
88 if ( !ads_cldap_netlogon(addr, ads->server.realm, &reply ) ) {
89 d_fprintf(stderr, "CLDAP query failed!\n");
90 return -1;
93 d_printf("Information for Domain Controller: %s\n\n",
94 addr);
96 d_printf("Response Type: ");
97 switch (reply.type) {
98 case SAMLOGON_AD_UNK_R:
99 d_printf("SAMLOGON\n");
100 break;
101 case SAMLOGON_AD_R:
102 d_printf("SAMLOGON_USER\n");
103 break;
104 default:
105 d_printf("0x%x\n", reply.type);
106 break;
109 smb_uuid_unpack(reply.guid, &tmp_guid);
110 d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), tmp_guid));
112 d_printf("Flags:\n"
113 "\tIs a PDC: %s\n"
114 "\tIs a GC of the forest: %s\n"
115 "\tIs an LDAP server: %s\n"
116 "\tSupports DS: %s\n"
117 "\tIs running a KDC: %s\n"
118 "\tIs running time services: %s\n"
119 "\tIs the closest DC: %s\n"
120 "\tIs writable: %s\n"
121 "\tHas a hardware clock: %s\n"
122 "\tIs a non-domain NC serviced by LDAP server: %s\n",
123 (reply.flags & ADS_PDC) ? "yes" : "no",
124 (reply.flags & ADS_GC) ? "yes" : "no",
125 (reply.flags & ADS_LDAP) ? "yes" : "no",
126 (reply.flags & ADS_DS) ? "yes" : "no",
127 (reply.flags & ADS_KDC) ? "yes" : "no",
128 (reply.flags & ADS_TIMESERV) ? "yes" : "no",
129 (reply.flags & ADS_CLOSEST) ? "yes" : "no",
130 (reply.flags & ADS_WRITABLE) ? "yes" : "no",
131 (reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
132 (reply.flags & ADS_NDNC) ? "yes" : "no");
134 printf("Forest:\t\t\t%s\n", reply.forest);
135 printf("Domain:\t\t\t%s\n", reply.domain);
136 printf("Domain Controller:\t%s\n", reply.hostname);
138 printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
139 printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
141 if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
142 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
144 printf("Server Site Name :\t\t%s\n", reply.server_site_name);
145 printf("Client Site Name :\t\t%s\n", reply.client_site_name);
147 d_printf("NT Version: %d\n", reply.version);
148 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
149 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
151 return 0;
155 this implements the CLDAP based netlogon lookup requests
156 for finding the domain controller of a ADS domain
158 static int net_ads_lookup(int argc, const char **argv)
160 ADS_STRUCT *ads;
162 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
163 d_fprintf(stderr, "Didn't find the cldap server!\n");
164 return -1;
167 if (!ads->config.realm) {
168 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
169 ads->ldap.port = 389;
172 return net_ads_cldap_netlogon(ads);
177 static int net_ads_info(int argc, const char **argv)
179 ADS_STRUCT *ads;
180 char addr[INET6_ADDRSTRLEN];
182 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
183 d_fprintf(stderr, "Didn't find the ldap server!\n");
184 return -1;
187 if (!ads || !ads->config.realm) {
188 d_fprintf(stderr, "Didn't find the ldap server!\n");
189 return -1;
192 /* Try to set the server's current time since we didn't do a full
193 TCP LDAP session initially */
195 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
196 d_fprintf( stderr, "Failed to get server's current time!\n");
199 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
201 d_printf("LDAP server: %s\n", addr);
202 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
203 d_printf("Realm: %s\n", ads->config.realm);
204 d_printf("Bind Path: %s\n", ads->config.bind_path);
205 d_printf("LDAP port: %d\n", ads->ldap.port);
206 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
208 d_printf("KDC server: %s\n", ads->auth.kdc_server );
209 d_printf("Server time offset: %d\n", ads->auth.time_offset );
211 return 0;
214 static void use_in_memory_ccache(void) {
215 /* Use in-memory credentials cache so we do not interfere with
216 * existing credentials */
217 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
220 static ADS_STATUS ads_startup_int(bool only_own_domain, uint32 auth_flags, ADS_STRUCT **ads_ret)
222 ADS_STRUCT *ads = NULL;
223 ADS_STATUS status;
224 bool need_password = False;
225 bool second_time = False;
226 char *cp;
227 const char *realm = NULL;
228 bool tried_closest_dc = False;
230 /* lp_realm() should be handled by a command line param,
231 However, the join requires that realm be set in smb.conf
232 and compares our realm with the remote server's so this is
233 ok until someone needs more flexibility */
235 *ads_ret = NULL;
237 retry_connect:
238 if (only_own_domain) {
239 realm = lp_realm();
240 } else {
241 realm = assume_own_realm();
244 ads = ads_init(realm, opt_target_workgroup, opt_host);
246 if (!opt_user_name) {
247 opt_user_name = "administrator";
250 if (opt_user_specified) {
251 need_password = True;
254 retry:
255 if (!opt_password && need_password && !opt_machine_pass) {
256 opt_password = net_prompt_pass(opt_user_name);
257 if (!opt_password) {
258 ads_destroy(&ads);
259 return ADS_ERROR(LDAP_NO_MEMORY);
263 if (opt_password) {
264 use_in_memory_ccache();
265 SAFE_FREE(ads->auth.password);
266 ads->auth.password = smb_xstrdup(opt_password);
269 ads->auth.flags |= auth_flags;
270 SAFE_FREE(ads->auth.user_name);
271 ads->auth.user_name = smb_xstrdup(opt_user_name);
274 * If the username is of the form "name@realm",
275 * extract the realm and convert to upper case.
276 * This is only used to establish the connection.
278 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
279 *cp++ = '\0';
280 SAFE_FREE(ads->auth.realm);
281 ads->auth.realm = smb_xstrdup(cp);
282 strupper_m(ads->auth.realm);
285 status = ads_connect(ads);
287 if (!ADS_ERR_OK(status)) {
289 if (NT_STATUS_EQUAL(ads_ntstatus(status),
290 NT_STATUS_NO_LOGON_SERVERS)) {
291 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
292 ads_destroy(&ads);
293 return status;
296 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
297 need_password = True;
298 second_time = True;
299 goto retry;
300 } else {
301 ads_destroy(&ads);
302 return status;
306 /* when contacting our own domain, make sure we use the closest DC.
307 * This is done by reconnecting to ADS because only the first call to
308 * ads_connect will give us our own sitename */
310 if ((only_own_domain || !opt_host) && !tried_closest_dc) {
312 tried_closest_dc = True; /* avoid loop */
314 if (!ads->config.tried_closest_dc) {
316 namecache_delete(ads->server.realm, 0x1C);
317 namecache_delete(ads->server.workgroup, 0x1C);
319 ads_destroy(&ads);
320 ads = NULL;
322 goto retry_connect;
326 *ads_ret = ads;
327 return status;
330 ADS_STATUS ads_startup(bool only_own_domain, ADS_STRUCT **ads)
332 return ads_startup_int(only_own_domain, 0, ads);
335 ADS_STATUS ads_startup_nobind(bool only_own_domain, ADS_STRUCT **ads)
337 return ads_startup_int(only_own_domain, ADS_AUTH_NO_BIND, ads);
341 Check to see if connection can be made via ads.
342 ads_startup() stores the password in opt_password if it needs to so
343 that rpc or rap can use it without re-prompting.
345 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
347 ADS_STRUCT *ads;
348 ADS_STATUS status;
350 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
351 return -1;
354 ads->auth.flags |= ADS_AUTH_NO_BIND;
356 status = ads_connect(ads);
357 if ( !ADS_ERR_OK(status) ) {
358 return -1;
361 ads_destroy(&ads);
362 return 0;
365 int net_ads_check_our_domain(void)
367 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
370 int net_ads_check(void)
372 return net_ads_check_int(NULL, opt_workgroup, opt_host);
376 determine the netbios workgroup name for a domain
378 static int net_ads_workgroup(int argc, const char **argv)
380 ADS_STRUCT *ads;
381 char addr[INET6_ADDRSTRLEN];
382 struct cldap_netlogon_reply reply;
384 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
385 d_fprintf(stderr, "Didn't find the cldap server!\n");
386 return -1;
389 if (!ads->config.realm) {
390 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
391 ads->ldap.port = 389;
394 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
395 if ( !ads_cldap_netlogon(addr, ads->server.realm, &reply ) ) {
396 d_fprintf(stderr, "CLDAP query failed!\n");
397 return -1;
400 d_printf("Workgroup: %s\n", reply.netbios_domain);
402 ads_destroy(&ads);
404 return 0;
409 static bool usergrp_display(ADS_STRUCT *ads, 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], '$')) {
416 if (disp_fields[1])
417 d_printf("%-21.21s %s\n",
418 disp_fields[0], disp_fields[1]);
419 else
420 d_printf("%s\n", disp_fields[0]);
423 SAFE_FREE(disp_fields[0]);
424 SAFE_FREE(disp_fields[1]);
425 return True;
427 if (!values) /* must be new field, indicate string field */
428 return True;
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]);
434 return True;
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)
444 ADS_STRUCT *ads;
445 ADS_STATUS status;
446 char *upn, *userdn;
447 LDAPMessage *res=NULL;
448 int rc = -1;
449 char *ou_str = NULL;
451 if (argc < 1) return net_ads_user_usage(argc, argv);
453 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
454 return -1;
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));
461 goto done;
464 if (ads_count_replies(ads, res)) {
465 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
466 goto done;
469 if (opt_container) {
470 ou_str = SMB_STRDUP(opt_container);
471 } else {
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],
479 ads_errstr(status));
480 goto done;
483 /* if no password is to be set, we're done */
484 if (argc == 1) {
485 d_printf("User %s added\n", argv[0]);
486 rc = 0;
487 goto done;
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);
494 safe_free(upn);
495 if (ADS_ERR_OK(status)) {
496 d_printf("User %s added\n", argv[0]);
497 rc = 0;
498 goto done;
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);
512 done:
513 if (res)
514 ads_msgfree(ads, res);
515 ads_destroy(&ads);
516 SAFE_FREE(ou_str);
517 return rc;
520 static int ads_user_info(int argc, const char **argv)
522 ADS_STRUCT *ads;
523 ADS_STATUS rc;
524 LDAPMessage *res;
525 const char *attrs[] = {"memberOf", NULL};
526 char *searchstring=NULL;
527 char **grouplist;
528 char *escaped_user;
530 if (argc < 1) {
531 return net_ads_user_usage(argc, argv);
534 escaped_user = escape_ldap_string_alloc(argv[0]);
536 if (!escaped_user) {
537 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
538 return -1;
541 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
542 SAFE_FREE(escaped_user);
543 return -1;
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));
552 ads_destroy(&ads);
553 SAFE_FREE(escaped_user);
554 return -1;
557 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
558 (LDAPMessage *)res, "memberOf");
560 if (grouplist) {
561 int i;
562 char **groupname;
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);
572 ads_destroy(&ads);
573 SAFE_FREE(escaped_user);
574 return 0;
577 static int ads_user_delete(int argc, const char **argv)
579 ADS_STRUCT *ads;
580 ADS_STATUS rc;
581 LDAPMessage *res = NULL;
582 char *userdn;
584 if (argc < 1) {
585 return net_ads_user_usage(argc, argv);
588 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
589 return -1;
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);
596 ads_destroy(&ads);
597 return -1;
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]);
605 ads_destroy(&ads);
606 return 0;
608 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
609 ads_errstr(rc));
610 ads_destroy(&ads);
611 return -1;
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},
620 {NULL, NULL}
622 ADS_STRUCT *ads;
623 ADS_STATUS rc;
624 const char *shortattrs[] = {"sAMAccountName", NULL};
625 const char *longattrs[] = {"sAMAccountName", "description", NULL};
626 char *disp_fields[2] = {NULL, NULL};
628 if (argc == 0) {
629 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
630 return -1;
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,
638 LDAP_SCOPE_SUBTREE,
639 "(objectCategory=user)",
640 opt_long_list_entries ? longattrs :
641 shortattrs, usergrp_display,
642 disp_fields);
643 ads_destroy(&ads);
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)
657 ADS_STRUCT *ads;
658 ADS_STATUS status;
659 LDAPMessage *res=NULL;
660 int rc = -1;
661 char *ou_str = NULL;
663 if (argc < 1) {
664 return net_ads_group_usage(argc, argv);
667 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
668 return -1;
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));
675 goto done;
678 if (ads_count_replies(ads, res)) {
679 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
680 goto done;
683 if (opt_container) {
684 ou_str = SMB_STRDUP(opt_container);
685 } else {
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]);
693 rc = 0;
694 } else {
695 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
696 ads_errstr(status));
699 done:
700 if (res)
701 ads_msgfree(ads, res);
702 ads_destroy(&ads);
703 SAFE_FREE(ou_str);
704 return rc;
707 static int ads_group_delete(int argc, const char **argv)
709 ADS_STRUCT *ads;
710 ADS_STATUS rc;
711 LDAPMessage *res = NULL;
712 char *groupdn;
714 if (argc < 1) {
715 return net_ads_group_usage(argc, argv);
718 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
719 return -1;
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);
726 ads_destroy(&ads);
727 return -1;
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]);
735 ads_destroy(&ads);
736 return 0;
738 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
739 ads_errstr(rc));
740 ads_destroy(&ads);
741 return -1;
744 int net_ads_group(int argc, const char **argv)
746 struct functable func[] = {
747 {"ADD", ads_group_add},
748 {"DELETE", ads_group_delete},
749 {NULL, NULL}
751 ADS_STRUCT *ads;
752 ADS_STATUS rc;
753 const char *shortattrs[] = {"sAMAccountName", NULL};
754 const char *longattrs[] = {"sAMAccountName", "description", NULL};
755 char *disp_fields[2] = {NULL, NULL};
757 if (argc == 0) {
758 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
759 return -1;
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,
766 LDAP_SCOPE_SUBTREE,
767 "(objectCategory=group)",
768 opt_long_list_entries ? longattrs :
769 shortattrs, usergrp_display,
770 disp_fields);
772 ads_destroy(&ads);
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)
780 ADS_STRUCT *ads;
781 ADS_STATUS rc;
782 LDAPMessage *res;
784 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
785 return -1;
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));
791 ads_destroy(&ads);
792 return -1;
795 if (ads_count_replies(ads, res) == 0) {
796 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
797 ads_destroy(&ads);
798 return -1;
801 ads_dump(ads, res);
802 ads_destroy(&ads);
803 return 0;
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 TALLOC_CTX *ctx;
816 struct libnet_UnjoinCtx *r = NULL;
817 WERROR werr;
819 if (!*lp_realm()) {
820 d_fprintf(stderr, "No realm set, are we joined ?\n");
821 return -1;
824 if (!(ctx = talloc_init("net_ads_leave"))) {
825 d_fprintf(stderr, "Could not initialise talloc context.\n");
826 return -1;
829 use_in_memory_ccache();
831 werr = libnet_init_UnjoinCtx(ctx, &r);
832 if (!W_ERROR_IS_OK(werr)) {
833 d_fprintf(stderr, "Could not initialise unjoin context.\n");
834 return -1;
837 r->in.debug = true;
838 r->in.dc_name = opt_host;
839 r->in.domain_name = lp_realm();
840 r->in.admin_account = opt_user_name;
841 r->in.admin_password = net_prompt_pass(opt_user_name);
842 r->in.modify_config = lp_config_backend_is_registry();
843 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
844 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
846 werr = libnet_Unjoin(ctx, r);
847 if (!W_ERROR_IS_OK(werr)) {
848 d_printf("Failed to leave domain: %s\n",
849 r->out.error_string ? r->out.error_string :
850 get_friendly_werror_msg(werr));
851 goto done;
854 if (W_ERROR_IS_OK(werr)) {
855 d_printf("Deleted account for '%s' in realm '%s'\n",
856 r->in.machine_name, r->out.dns_domain_name);
857 goto done;
860 /* We couldn't delete it - see if the disable succeeded. */
861 if (r->out.disabled_machine_account) {
862 d_printf("Disabled account for '%s' in realm '%s'\n",
863 r->in.machine_name, r->out.dns_domain_name);
864 werr = WERR_OK;
865 goto done;
868 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
869 r->in.machine_name, r->out.dns_domain_name);
871 done:
872 TALLOC_FREE(r);
873 TALLOC_FREE(ctx);
875 if (W_ERROR_IS_OK(werr)) {
876 return 0;
879 return -1;
882 static NTSTATUS net_ads_join_ok(void)
884 ADS_STRUCT *ads = NULL;
885 ADS_STATUS status;
887 if (!secrets_init()) {
888 DEBUG(1,("Failed to initialise secrets database\n"));
889 return NT_STATUS_ACCESS_DENIED;
892 net_use_krb_machine_account();
894 status = ads_startup(True, &ads);
895 if (!ADS_ERR_OK(status)) {
896 return ads_ntstatus(status);
899 ads_destroy(&ads);
900 return NT_STATUS_OK;
904 check that an existing join is OK
906 int net_ads_testjoin(int argc, const char **argv)
908 NTSTATUS status;
909 use_in_memory_ccache();
911 /* Display success or failure */
912 status = net_ads_join_ok();
913 if (!NT_STATUS_IS_OK(status)) {
914 fprintf(stderr,"Join to domain is not valid: %s\n",
915 get_friendly_nt_error_msg(status));
916 return -1;
919 printf("Join is OK\n");
920 return 0;
923 /*******************************************************************
924 Simple configu checks before beginning the join
925 ********************************************************************/
927 static WERROR check_ads_config( void )
929 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
930 d_printf("Host is not configured as a member server.\n");
931 return WERR_INVALID_DOMAIN_ROLE;
934 if (strlen(global_myname()) > 15) {
935 d_printf("Our netbios name can be at most 15 chars long, "
936 "\"%s\" is %u chars long\n", global_myname(),
937 (unsigned int)strlen(global_myname()));
938 return WERR_INVALID_COMPUTER_NAME;
941 if ( lp_security() == SEC_ADS && !*lp_realm()) {
942 d_fprintf(stderr, "realm must be set in in %s for ADS "
943 "join to succeed.\n", get_dyn_CONFIGFILE());
944 return WERR_INVALID_PARAM;
947 return WERR_OK;
950 /*******************************************************************
951 Send a DNS update request
952 *******************************************************************/
954 #if defined(WITH_DNS_UPDATES)
955 #include "dns.h"
956 DNS_ERROR DoDNSUpdate(char *pszServerName,
957 const char *pszDomainName, const char *pszHostName,
958 const struct sockaddr_storage *sslist,
959 size_t num_addrs );
961 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
962 const char *machine_name,
963 const struct sockaddr_storage *addrs,
964 int num_addrs)
966 struct dns_rr_ns *nameservers = NULL;
967 int ns_count = 0;
968 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
969 DNS_ERROR dns_err;
970 fstring dns_server;
971 const char *dnsdomain = NULL;
972 char *root_domain = NULL;
974 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
975 d_printf("No DNS domain configured for %s. "
976 "Unable to perform DNS Update.\n", machine_name);
977 status = NT_STATUS_INVALID_PARAMETER;
978 goto done;
980 dnsdomain++;
982 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
983 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
984 /* Child domains often do not have NS records. Look
985 for the NS record for the forest root domain
986 (rootDomainNamingContext in therootDSE) */
988 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
989 LDAPMessage *msg = NULL;
990 char *root_dn;
991 ADS_STATUS ads_status;
993 if ( !ads->ldap.ld ) {
994 ads_status = ads_connect( ads );
995 if ( !ADS_ERR_OK(ads_status) ) {
996 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
997 goto done;
1001 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1002 "(objectclass=*)", rootname_attrs, &msg);
1003 if (!ADS_ERR_OK(ads_status)) {
1004 goto done;
1007 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1008 if ( !root_dn ) {
1009 ads_msgfree( ads, msg );
1010 goto done;
1013 root_domain = ads_build_domain( root_dn );
1015 /* cleanup */
1016 ads_msgfree( ads, msg );
1018 /* try again for NS servers */
1020 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1022 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1023 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1024 "realm\n", ads->config.realm));
1025 goto done;
1028 dnsdomain = root_domain;
1032 /* Now perform the dns update - we'll try non-secure and if we fail,
1033 we'll follow it up with a secure update */
1035 fstrcpy( dns_server, nameservers[0].hostname );
1037 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1038 if (!ERR_DNS_IS_OK(dns_err)) {
1039 status = NT_STATUS_UNSUCCESSFUL;
1042 done:
1044 SAFE_FREE( root_domain );
1046 return status;
1049 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1051 int num_addrs;
1052 struct sockaddr_storage *iplist = NULL;
1053 fstring machine_name;
1054 NTSTATUS status;
1056 name_to_fqdn( machine_name, global_myname() );
1057 strlower_m( machine_name );
1059 /* Get our ip address (not the 127.0.0.x address but a real ip
1060 * address) */
1062 num_addrs = get_my_ip_address( &iplist );
1063 if ( num_addrs <= 0 ) {
1064 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1065 "addresses!\n"));
1066 return NT_STATUS_INVALID_PARAMETER;
1069 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1070 iplist, num_addrs);
1071 SAFE_FREE( iplist );
1072 return status;
1074 #endif
1077 /*******************************************************************
1078 ********************************************************************/
1080 static int net_ads_join_usage(int argc, const char **argv)
1082 d_printf("net ads join [options]\n");
1083 d_printf("Valid options:\n");
1084 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1085 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1086 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1087 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1088 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1089 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1090 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1091 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1092 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1093 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1094 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1095 d_printf(" the two other attributes.\n");
1097 return -1;
1100 /*******************************************************************
1101 ********************************************************************/
1103 int net_ads_join(int argc, const char **argv)
1105 TALLOC_CTX *ctx = NULL;
1106 struct libnet_JoinCtx *r = NULL;
1107 const char *domain = lp_realm();
1108 WERROR werr = WERR_SETUP_NOT_JOINED;
1109 bool createupn = False;
1110 const char *machineupn = NULL;
1111 const char *create_in_ou = NULL;
1112 int i;
1113 const char *os_name = NULL;
1114 const char *os_version = NULL;
1115 bool modify_config = lp_config_backend_is_registry();
1117 if (!modify_config) {
1119 werr = check_ads_config();
1120 if (!W_ERROR_IS_OK(werr)) {
1121 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1122 goto fail;
1126 if (!(ctx = talloc_init("net_ads_join"))) {
1127 d_fprintf(stderr, "Could not initialise talloc context.\n");
1128 werr = WERR_NOMEM;
1129 goto fail;
1132 use_in_memory_ccache();
1134 werr = libnet_init_JoinCtx(ctx, &r);
1135 if (!W_ERROR_IS_OK(werr)) {
1136 goto fail;
1139 /* process additional command line args */
1141 for ( i=0; i<argc; i++ ) {
1142 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1143 createupn = True;
1144 machineupn = get_string_param(argv[i]);
1146 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1147 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1148 d_fprintf(stderr, "Please supply a valid OU path.\n");
1149 werr = WERR_INVALID_PARAM;
1150 goto fail;
1153 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1154 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1155 d_fprintf(stderr, "Please supply a operating system name.\n");
1156 werr = WERR_INVALID_PARAM;
1157 goto fail;
1160 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1161 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1162 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1163 werr = WERR_INVALID_PARAM;
1164 goto fail;
1167 else {
1168 domain = argv[i];
1172 if (!*domain) {
1173 d_fprintf(stderr, "Please supply a valid domain name\n");
1174 werr = WERR_INVALID_PARAM;
1175 goto fail;
1178 /* Do the domain join here */
1180 r->in.domain_name = domain;
1181 r->in.create_upn = createupn;
1182 r->in.upn = machineupn;
1183 r->in.account_ou = create_in_ou;
1184 r->in.os_name = os_name;
1185 r->in.os_version = os_version;
1186 r->in.dc_name = opt_host;
1187 r->in.admin_account = opt_user_name;
1188 r->in.admin_password = net_prompt_pass(opt_user_name);
1189 r->in.debug = true;
1190 r->in.modify_config = modify_config;
1191 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1192 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1193 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1195 werr = libnet_Join(ctx, r);
1196 if (!W_ERROR_IS_OK(werr)) {
1197 goto fail;
1200 /* Check the short name of the domain */
1202 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1203 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1204 d_printf("domain name obtained from the server.\n");
1205 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1206 d_printf("You should set \"workgroup = %s\" in %s.\n",
1207 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1210 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1212 if (r->out.dns_domain_name) {
1213 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1214 r->out.dns_domain_name);
1215 } else {
1216 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1217 r->out.netbios_domain_name);
1220 #if defined(WITH_DNS_UPDATES)
1221 if (r->out.domain_is_ad) {
1222 /* We enter this block with user creds */
1223 ADS_STRUCT *ads_dns = NULL;
1225 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1226 /* kinit with the machine password */
1228 use_in_memory_ccache();
1229 asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1230 ads_dns->auth.password = secrets_fetch_machine_password(
1231 r->out.netbios_domain_name, NULL, NULL );
1232 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1233 ads_kinit_password( ads_dns );
1236 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1237 d_fprintf( stderr, "DNS update failed!\n" );
1240 /* exit from this block using machine creds */
1241 ads_destroy(&ads_dns);
1243 #endif
1244 TALLOC_FREE(r);
1245 TALLOC_FREE( ctx );
1247 return 0;
1249 fail:
1250 /* issue an overall failure message at the end. */
1251 d_printf("Failed to join domain: %s\n",
1252 r && r->out.error_string ? r->out.error_string :
1253 get_friendly_werror_msg(werr));
1254 TALLOC_FREE( ctx );
1256 return -1;
1259 /*******************************************************************
1260 ********************************************************************/
1262 static int net_ads_dns_usage(int argc, const char **argv)
1264 #if defined(WITH_DNS_UPDATES)
1265 d_printf("net ads dns <command>\n");
1266 d_printf("Valid commands:\n");
1267 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1269 return 0;
1270 #else
1271 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1272 return -1;
1273 #endif
1276 /*******************************************************************
1277 ********************************************************************/
1279 static int net_ads_dns_register(int argc, const char **argv)
1281 #if defined(WITH_DNS_UPDATES)
1282 ADS_STRUCT *ads;
1283 ADS_STATUS status;
1284 TALLOC_CTX *ctx;
1286 #ifdef DEVELOPER
1287 talloc_enable_leak_report();
1288 #endif
1290 if (argc > 0) {
1291 d_fprintf(stderr, "net ads dns register\n");
1292 return -1;
1295 if (!(ctx = talloc_init("net_ads_dns"))) {
1296 d_fprintf(stderr, "Could not initialise talloc context\n");
1297 return -1;
1300 status = ads_startup(True, &ads);
1301 if ( !ADS_ERR_OK(status) ) {
1302 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1303 TALLOC_FREE(ctx);
1304 return -1;
1307 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1308 d_fprintf( stderr, "DNS update failed!\n" );
1309 ads_destroy( &ads );
1310 TALLOC_FREE( ctx );
1311 return -1;
1314 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1316 ads_destroy(&ads);
1317 TALLOC_FREE( ctx );
1319 return 0;
1320 #else
1321 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1322 return -1;
1323 #endif
1326 #if defined(WITH_DNS_UPDATES)
1327 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1328 #endif
1330 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1332 #if defined(WITH_DNS_UPDATES)
1333 DNS_ERROR err;
1335 #ifdef DEVELOPER
1336 talloc_enable_leak_report();
1337 #endif
1339 if (argc != 2) {
1340 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1341 "<name>\n");
1342 return -1;
1345 err = do_gethostbyname(argv[0], argv[1]);
1347 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1348 #endif
1349 return 0;
1352 static int net_ads_dns(int argc, const char *argv[])
1354 struct functable func[] = {
1355 {"REGISTER", net_ads_dns_register},
1356 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1357 {NULL, NULL}
1360 return net_run_function(argc, argv, func, net_ads_dns_usage);
1363 /*******************************************************************
1364 ********************************************************************/
1366 int net_ads_printer_usage(int argc, const char **argv)
1368 d_printf(
1369 "\nnet ads printer search <printer>"
1370 "\n\tsearch for a printer in the directory\n"
1371 "\nnet ads printer info <printer> <server>"
1372 "\n\tlookup info in directory for printer on server"
1373 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1374 "\nnet ads printer publish <printername>"
1375 "\n\tpublish printer in directory"
1376 "\n\t(note: printer name is required)\n"
1377 "\nnet ads printer remove <printername>"
1378 "\n\tremove printer from directory"
1379 "\n\t(note: printer name is required)\n");
1380 return -1;
1383 /*******************************************************************
1384 ********************************************************************/
1386 static int net_ads_printer_search(int argc, const char **argv)
1388 ADS_STRUCT *ads;
1389 ADS_STATUS rc;
1390 LDAPMessage *res = NULL;
1392 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1393 return -1;
1396 rc = ads_find_printers(ads, &res);
1398 if (!ADS_ERR_OK(rc)) {
1399 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1400 ads_msgfree(ads, res);
1401 ads_destroy(&ads);
1402 return -1;
1405 if (ads_count_replies(ads, res) == 0) {
1406 d_fprintf(stderr, "No results found\n");
1407 ads_msgfree(ads, res);
1408 ads_destroy(&ads);
1409 return -1;
1412 ads_dump(ads, res);
1413 ads_msgfree(ads, res);
1414 ads_destroy(&ads);
1415 return 0;
1418 static int net_ads_printer_info(int argc, const char **argv)
1420 ADS_STRUCT *ads;
1421 ADS_STATUS rc;
1422 const char *servername, *printername;
1423 LDAPMessage *res = NULL;
1425 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1426 return -1;
1429 if (argc > 0) {
1430 printername = argv[0];
1431 } else {
1432 printername = "*";
1435 if (argc > 1) {
1436 servername = argv[1];
1437 } else {
1438 servername = global_myname();
1441 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1443 if (!ADS_ERR_OK(rc)) {
1444 d_fprintf(stderr, "Server '%s' not found: %s\n",
1445 servername, ads_errstr(rc));
1446 ads_msgfree(ads, res);
1447 ads_destroy(&ads);
1448 return -1;
1451 if (ads_count_replies(ads, res) == 0) {
1452 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1453 ads_msgfree(ads, res);
1454 ads_destroy(&ads);
1455 return -1;
1458 ads_dump(ads, res);
1459 ads_msgfree(ads, res);
1460 ads_destroy(&ads);
1462 return 0;
1465 static int net_ads_printer_publish(int argc, const char **argv)
1467 ADS_STRUCT *ads;
1468 ADS_STATUS rc;
1469 const char *servername, *printername;
1470 struct cli_state *cli;
1471 struct rpc_pipe_client *pipe_hnd;
1472 struct sockaddr_storage server_ss;
1473 NTSTATUS nt_status;
1474 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1475 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1476 char *prt_dn, *srv_dn, **srv_cn;
1477 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1478 LDAPMessage *res = NULL;
1480 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1481 talloc_destroy(mem_ctx);
1482 return -1;
1485 if (argc < 1) {
1486 talloc_destroy(mem_ctx);
1487 return net_ads_printer_usage(argc, argv);
1490 printername = argv[0];
1492 if (argc == 2) {
1493 servername = argv[1];
1494 } else {
1495 servername = global_myname();
1498 /* Get printer data from SPOOLSS */
1500 resolve_name(servername, &server_ss, 0x20);
1502 nt_status = cli_full_connection(&cli, global_myname(), servername,
1503 &server_ss, 0,
1504 "IPC$", "IPC",
1505 opt_user_name, opt_workgroup,
1506 opt_password ? opt_password : "",
1507 CLI_FULL_CONNECTION_USE_KERBEROS,
1508 Undefined, NULL);
1510 if (NT_STATUS_IS_ERR(nt_status)) {
1511 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1512 "for %s\n", servername, printername);
1513 ads_destroy(&ads);
1514 talloc_destroy(mem_ctx);
1515 return -1;
1518 /* Publish on AD server */
1520 ads_find_machine_acct(ads, &res, servername);
1522 if (ads_count_replies(ads, res) == 0) {
1523 d_fprintf(stderr, "Could not find machine account for server %s\n",
1524 servername);
1525 ads_destroy(&ads);
1526 talloc_destroy(mem_ctx);
1527 return -1;
1530 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1531 srv_cn = ldap_explode_dn(srv_dn, 1);
1533 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1534 printername_escaped = escape_rdn_val_string_alloc(printername);
1535 if (!srv_cn_escaped || !printername_escaped) {
1536 SAFE_FREE(srv_cn_escaped);
1537 SAFE_FREE(printername_escaped);
1538 d_fprintf(stderr, "Internal error, out of memory!");
1539 ads_destroy(&ads);
1540 talloc_destroy(mem_ctx);
1541 return -1;
1544 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1546 SAFE_FREE(srv_cn_escaped);
1547 SAFE_FREE(printername_escaped);
1549 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1550 if (!pipe_hnd) {
1551 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1552 servername);
1553 SAFE_FREE(prt_dn);
1554 ads_destroy(&ads);
1555 talloc_destroy(mem_ctx);
1556 return -1;
1559 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1560 printername))) {
1561 SAFE_FREE(prt_dn);
1562 ads_destroy(&ads);
1563 talloc_destroy(mem_ctx);
1564 return -1;
1567 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1568 if (!ADS_ERR_OK(rc)) {
1569 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1570 SAFE_FREE(prt_dn);
1571 ads_destroy(&ads);
1572 talloc_destroy(mem_ctx);
1573 return -1;
1576 d_printf("published printer\n");
1577 SAFE_FREE(prt_dn);
1578 ads_destroy(&ads);
1579 talloc_destroy(mem_ctx);
1581 return 0;
1584 static int net_ads_printer_remove(int argc, const char **argv)
1586 ADS_STRUCT *ads;
1587 ADS_STATUS rc;
1588 const char *servername;
1589 char *prt_dn;
1590 LDAPMessage *res = NULL;
1592 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1593 return -1;
1596 if (argc < 1) {
1597 return net_ads_printer_usage(argc, argv);
1600 if (argc > 1) {
1601 servername = argv[1];
1602 } else {
1603 servername = global_myname();
1606 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1608 if (!ADS_ERR_OK(rc)) {
1609 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1610 ads_msgfree(ads, res);
1611 ads_destroy(&ads);
1612 return -1;
1615 if (ads_count_replies(ads, res) == 0) {
1616 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1617 ads_msgfree(ads, res);
1618 ads_destroy(&ads);
1619 return -1;
1622 prt_dn = ads_get_dn(ads, res);
1623 ads_msgfree(ads, res);
1624 rc = ads_del_dn(ads, prt_dn);
1625 ads_memfree(ads, prt_dn);
1627 if (!ADS_ERR_OK(rc)) {
1628 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1629 ads_destroy(&ads);
1630 return -1;
1633 ads_destroy(&ads);
1634 return 0;
1637 static int net_ads_printer(int argc, const char **argv)
1639 struct functable func[] = {
1640 {"SEARCH", net_ads_printer_search},
1641 {"INFO", net_ads_printer_info},
1642 {"PUBLISH", net_ads_printer_publish},
1643 {"REMOVE", net_ads_printer_remove},
1644 {NULL, NULL}
1647 return net_run_function(argc, argv, func, net_ads_printer_usage);
1651 static int net_ads_password(int argc, const char **argv)
1653 ADS_STRUCT *ads;
1654 const char *auth_principal = opt_user_name;
1655 const char *auth_password = opt_password;
1656 char *realm = NULL;
1657 char *new_password = NULL;
1658 char *c, *prompt;
1659 const char *user;
1660 ADS_STATUS ret;
1662 if (opt_user_name == NULL || opt_password == NULL) {
1663 d_fprintf(stderr, "You must supply an administrator username/password\n");
1664 return -1;
1667 if (argc < 1) {
1668 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1669 return -1;
1672 user = argv[0];
1673 if (!strchr_m(user, '@')) {
1674 asprintf(&c, "%s@%s", argv[0], lp_realm());
1675 user = c;
1678 use_in_memory_ccache();
1679 c = strchr_m(auth_principal, '@');
1680 if (c) {
1681 realm = ++c;
1682 } else {
1683 realm = lp_realm();
1686 /* use the realm so we can eventually change passwords for users
1687 in realms other than default */
1688 if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
1689 return -1;
1692 /* we don't actually need a full connect, but it's the easy way to
1693 fill in the KDC's addresss */
1694 ads_connect(ads);
1696 if (!ads->config.realm) {
1697 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1698 return -1;
1701 if (argv[1]) {
1702 new_password = (char *)argv[1];
1703 } else {
1704 asprintf(&prompt, "Enter new password for %s:", user);
1705 new_password = getpass(prompt);
1706 free(prompt);
1709 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1710 auth_password, user, new_password, ads->auth.time_offset);
1711 if (!ADS_ERR_OK(ret)) {
1712 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1713 ads_destroy(&ads);
1714 return -1;
1717 d_printf("Password change for %s completed.\n", user);
1718 ads_destroy(&ads);
1720 return 0;
1723 int net_ads_changetrustpw(int argc, const char **argv)
1725 ADS_STRUCT *ads;
1726 char *host_principal;
1727 fstring my_name;
1728 ADS_STATUS ret;
1730 if (!secrets_init()) {
1731 DEBUG(1,("Failed to initialise secrets database\n"));
1732 return -1;
1735 net_use_krb_machine_account();
1737 use_in_memory_ccache();
1739 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1740 return -1;
1743 fstrcpy(my_name, global_myname());
1744 strlower_m(my_name);
1745 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1746 d_printf("Changing password for principal: %s\n", host_principal);
1748 ret = ads_change_trust_account_password(ads, host_principal);
1750 if (!ADS_ERR_OK(ret)) {
1751 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1752 ads_destroy(&ads);
1753 SAFE_FREE(host_principal);
1754 return -1;
1757 d_printf("Password change for principal %s succeeded.\n", host_principal);
1759 if (lp_use_kerberos_keytab()) {
1760 d_printf("Attempting to update system keytab with new password.\n");
1761 if (ads_keytab_create_default(ads)) {
1762 d_printf("Failed to update system keytab.\n");
1766 ads_destroy(&ads);
1767 SAFE_FREE(host_principal);
1769 return 0;
1773 help for net ads search
1775 static int net_ads_search_usage(int argc, const char **argv)
1777 d_printf(
1778 "\nnet ads search <expression> <attributes...>\n"\
1779 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1780 "The expression is a standard LDAP search expression, and the\n"\
1781 "attributes are a list of LDAP fields to show in the results\n\n"\
1782 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1784 net_common_flags_usage(argc, argv);
1785 return -1;
1790 general ADS search function. Useful in diagnosing problems in ADS
1792 static int net_ads_search(int argc, const char **argv)
1794 ADS_STRUCT *ads;
1795 ADS_STATUS rc;
1796 const char *ldap_exp;
1797 const char **attrs;
1798 LDAPMessage *res = NULL;
1800 if (argc < 1) {
1801 return net_ads_search_usage(argc, argv);
1804 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1805 return -1;
1808 ldap_exp = argv[0];
1809 attrs = (argv + 1);
1811 rc = ads_do_search_all(ads, ads->config.bind_path,
1812 LDAP_SCOPE_SUBTREE,
1813 ldap_exp, attrs, &res);
1814 if (!ADS_ERR_OK(rc)) {
1815 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1816 ads_destroy(&ads);
1817 return -1;
1820 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1822 /* dump the results */
1823 ads_dump(ads, res);
1825 ads_msgfree(ads, res);
1826 ads_destroy(&ads);
1828 return 0;
1833 help for net ads search
1835 static int net_ads_dn_usage(int argc, const char **argv)
1837 d_printf(
1838 "\nnet ads dn <dn> <attributes...>\n"\
1839 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1840 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1841 "to show in the results\n\n"\
1842 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1843 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1845 net_common_flags_usage(argc, argv);
1846 return -1;
1851 general ADS search function. Useful in diagnosing problems in ADS
1853 static int net_ads_dn(int argc, const char **argv)
1855 ADS_STRUCT *ads;
1856 ADS_STATUS rc;
1857 const char *dn;
1858 const char **attrs;
1859 LDAPMessage *res = NULL;
1861 if (argc < 1) {
1862 return net_ads_dn_usage(argc, argv);
1865 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1866 return -1;
1869 dn = argv[0];
1870 attrs = (argv + 1);
1872 rc = ads_do_search_all(ads, dn,
1873 LDAP_SCOPE_BASE,
1874 "(objectclass=*)", attrs, &res);
1875 if (!ADS_ERR_OK(rc)) {
1876 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1877 ads_destroy(&ads);
1878 return -1;
1881 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1883 /* dump the results */
1884 ads_dump(ads, res);
1886 ads_msgfree(ads, res);
1887 ads_destroy(&ads);
1889 return 0;
1893 help for net ads sid search
1895 static int net_ads_sid_usage(int argc, const char **argv)
1897 d_printf(
1898 "\nnet ads sid <sid> <attributes...>\n"\
1899 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1900 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
1901 "to show in the results\n\n"\
1902 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
1904 net_common_flags_usage(argc, argv);
1905 return -1;
1910 general ADS search function. Useful in diagnosing problems in ADS
1912 static int net_ads_sid(int argc, const char **argv)
1914 ADS_STRUCT *ads;
1915 ADS_STATUS rc;
1916 const char *sid_string;
1917 const char **attrs;
1918 LDAPMessage *res = NULL;
1919 DOM_SID sid;
1921 if (argc < 1) {
1922 return net_ads_sid_usage(argc, argv);
1925 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1926 return -1;
1929 sid_string = argv[0];
1930 attrs = (argv + 1);
1932 if (!string_to_sid(&sid, sid_string)) {
1933 d_fprintf(stderr, "could not convert sid\n");
1934 ads_destroy(&ads);
1935 return -1;
1938 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
1939 if (!ADS_ERR_OK(rc)) {
1940 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1941 ads_destroy(&ads);
1942 return -1;
1945 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1947 /* dump the results */
1948 ads_dump(ads, res);
1950 ads_msgfree(ads, res);
1951 ads_destroy(&ads);
1953 return 0;
1957 static int net_ads_keytab_usage(int argc, const char **argv)
1959 d_printf(
1960 "net ads keytab <COMMAND>\n"\
1961 "<COMMAND> can be either:\n"\
1962 " ADD Adds new service principal\n"\
1963 " CREATE Creates a fresh keytab\n"\
1964 " FLUSH Flushes out all keytab entries\n"\
1965 " HELP Prints this help message\n"\
1966 " LIST List the keytab\n"\
1967 "The ADD and LIST command will take arguments, the other commands\n"\
1968 "will not take any arguments. The arguments given to ADD\n"\
1969 "should be a list of principals to add. For example, \n"\
1970 " net ads keytab add srv1 srv2\n"\
1971 "will add principals for the services srv1 and srv2 to the\n"\
1972 "system's keytab.\n"\
1973 "The LIST command takes a keytabname.\n"\
1974 "\n"
1976 return -1;
1979 static int net_ads_keytab_flush(int argc, const char **argv)
1981 int ret;
1982 ADS_STRUCT *ads;
1984 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1985 return -1;
1987 ret = ads_keytab_flush(ads);
1988 ads_destroy(&ads);
1989 return ret;
1992 static int net_ads_keytab_add(int argc, const char **argv)
1994 int i;
1995 int ret = 0;
1996 ADS_STRUCT *ads;
1998 d_printf("Processing principals to add...\n");
1999 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2000 return -1;
2002 for (i = 0; i < argc; i++) {
2003 ret |= ads_keytab_add_entry(ads, argv[i]);
2005 ads_destroy(&ads);
2006 return ret;
2009 static int net_ads_keytab_create(int argc, const char **argv)
2011 ADS_STRUCT *ads;
2012 int ret;
2014 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2015 return -1;
2017 ret = ads_keytab_create_default(ads);
2018 ads_destroy(&ads);
2019 return ret;
2022 static int net_ads_keytab_list(int argc, const char **argv)
2024 const char *keytab = NULL;
2026 if (argc >= 1) {
2027 keytab = argv[0];
2030 return ads_keytab_list(keytab);
2034 int net_ads_keytab(int argc, const char **argv)
2036 struct functable func[] = {
2037 {"ADD", net_ads_keytab_add},
2038 {"CREATE", net_ads_keytab_create},
2039 {"FLUSH", net_ads_keytab_flush},
2040 {"HELP", net_ads_keytab_usage},
2041 {"LIST", net_ads_keytab_list},
2042 {NULL, NULL}
2045 if (!lp_use_kerberos_keytab()) {
2046 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2047 use keytab functions.\n");
2050 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2053 static int net_ads_kerberos_usage(int argc, const char **argv)
2055 d_printf(
2056 "net ads kerberos <COMMAND>\n"\
2057 "<COMMAND> can be either:\n"\
2058 " RENEW Renew TGT from existing credential cache\n"\
2059 " PAC Dumps the Kerberos PAC\n"\
2060 " KINIT Retrieve Ticket Granting Ticket (TGT)\n"\
2061 "\n"
2064 return -1;
2067 static int net_ads_kerberos_renew(int argc, const char **argv)
2069 int ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2070 if (ret) {
2071 d_printf("failed to renew kerberos ticket: %s\n",
2072 error_message(ret));
2074 return ret;
2077 static int net_ads_kerberos_pac(int argc, const char **argv)
2079 struct PAC_DATA *pac = NULL;
2080 struct PAC_LOGON_INFO *info = NULL;
2081 TALLOC_CTX *mem_ctx = NULL;
2082 NTSTATUS status;
2083 int ret = -1;
2085 mem_ctx = talloc_init("net_ads_kerberos_pac");
2086 if (!mem_ctx) {
2087 goto out;
2090 opt_password = net_prompt_pass(opt_user_name);
2092 status = kerberos_return_pac(mem_ctx,
2093 opt_user_name,
2094 opt_password,
2096 NULL,
2097 NULL,
2098 NULL,
2099 True,
2100 True,
2101 2592000, /* one month */
2102 &pac);
2103 if (!NT_STATUS_IS_OK(status)) {
2104 d_printf("failed to query kerberos PAC: %s\n",
2105 nt_errstr(status));
2106 goto out;
2109 info = get_logon_info_from_pac(pac);
2110 if (info) {
2111 const char *s;
2112 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2113 d_printf("The Pac: %s\n", s);
2116 ret = 0;
2117 out:
2118 TALLOC_FREE(mem_ctx);
2119 return ret;
2122 static int net_ads_kerberos_kinit(int argc, const char **argv)
2124 TALLOC_CTX *mem_ctx = NULL;
2125 int ret = -1;
2126 NTSTATUS status;
2128 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2129 if (!mem_ctx) {
2130 goto out;
2133 opt_password = net_prompt_pass(opt_user_name);
2135 ret = kerberos_kinit_password_ext(opt_user_name,
2136 opt_password,
2138 NULL,
2139 NULL,
2140 NULL,
2141 True,
2142 True,
2143 2592000, /* one month */
2144 &status);
2145 if (ret) {
2146 d_printf("failed to kinit password: %s\n",
2147 nt_errstr(status));
2149 out:
2150 return ret;
2153 int net_ads_kerberos(int argc, const char **argv)
2155 struct functable func[] = {
2156 {"KINIT", net_ads_kerberos_kinit},
2157 {"RENEW", net_ads_kerberos_renew},
2158 {"PAC", net_ads_kerberos_pac},
2159 {"HELP", net_ads_kerberos_usage},
2160 {NULL, NULL}
2163 return net_run_function(argc, argv, func, net_ads_kerberos_usage);
2167 int net_ads_help(int argc, const char **argv)
2169 struct functable func[] = {
2170 {"USER", net_ads_user_usage},
2171 {"GROUP", net_ads_group_usage},
2172 {"PRINTER", net_ads_printer_usage},
2173 {"SEARCH", net_ads_search_usage},
2174 {"INFO", net_ads_info},
2175 {"JOIN", net_ads_join_usage},
2176 {"DNS", net_ads_dns_usage},
2177 {"LEAVE", net_ads_leave},
2178 {"STATUS", net_ads_status},
2179 {"PASSWORD", net_ads_password},
2180 {"CHANGETRUSTPW", net_ads_changetrustpw},
2181 {NULL, NULL}
2184 return net_run_function(argc, argv, func, net_ads_usage);
2187 int net_ads(int argc, const char **argv)
2189 struct functable func[] = {
2190 {"INFO", net_ads_info},
2191 {"JOIN", net_ads_join},
2192 {"TESTJOIN", net_ads_testjoin},
2193 {"LEAVE", net_ads_leave},
2194 {"STATUS", net_ads_status},
2195 {"USER", net_ads_user},
2196 {"GROUP", net_ads_group},
2197 {"DNS", net_ads_dns},
2198 {"PASSWORD", net_ads_password},
2199 {"CHANGETRUSTPW", net_ads_changetrustpw},
2200 {"PRINTER", net_ads_printer},
2201 {"SEARCH", net_ads_search},
2202 {"DN", net_ads_dn},
2203 {"SID", net_ads_sid},
2204 {"WORKGROUP", net_ads_workgroup},
2205 {"LOOKUP", net_ads_lookup},
2206 {"KEYTAB", net_ads_keytab},
2207 {"GPO", net_ads_gpo},
2208 {"KERBEROS", net_ads_kerberos},
2209 {"HELP", net_ads_help},
2210 {NULL, NULL}
2213 return net_run_function(argc, argv, func, net_ads_usage);
2216 #else
2218 static int net_ads_noads(void)
2220 d_fprintf(stderr, "ADS support not compiled in\n");
2221 return -1;
2224 int net_ads_keytab(int argc, const char **argv)
2226 return net_ads_noads();
2229 int net_ads_kerberos(int argc, const char **argv)
2231 return net_ads_noads();
2234 int net_ads_usage(int argc, const char **argv)
2236 return net_ads_noads();
2239 int net_ads_help(int argc, const char **argv)
2241 return net_ads_noads();
2244 int net_ads_changetrustpw(int argc, const char **argv)
2246 return net_ads_noads();
2249 int net_ads_join(int argc, const char **argv)
2251 return net_ads_noads();
2254 int net_ads_user(int argc, const char **argv)
2256 return net_ads_noads();
2259 int net_ads_group(int argc, const char **argv)
2261 return net_ads_noads();
2264 /* this one shouldn't display a message */
2265 int net_ads_check(void)
2267 return -1;
2270 int net_ads_check_our_domain(void)
2272 return -1;
2275 int net_ads(int argc, const char **argv)
2277 return net_ads_usage(argc, argv);
2280 #endif /* WITH_ADS */