s3-lsa: Fix Bug #6263. Unexpected LookupSids reply crashes XP pre-SP3.
[Samba.git] / source / utils / net_ads.c
bloba023a11a066171bd301703ca65dfcc29b6c14f24
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 #ifdef HAVE_ADS
28 int net_ads_usage(int argc, const char **argv)
30 d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
31 d_printf(" Join the local machine to a ADS realm\n");
32 d_printf("leave\n");
33 d_printf(" Remove the local machine from a ADS realm\n");
34 d_printf("testjoin\n");
35 d_printf(" Validates the machine account in the domain\n");
36 d_printf("user\n");
37 d_printf(" List, add, or delete users in the realm\n");
38 d_printf("group\n");
39 d_printf(" List, add, or delete groups in the realm\n");
40 d_printf("info\n");
41 d_printf(" Displays details regarding a specific AD server\n");
42 d_printf("status\n");
43 d_printf(" Display details regarding the machine's account in AD\n");
44 d_printf("lookup\n");
45 d_printf(" Performs CLDAP query of AD domain controllers\n");
46 d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
47 d_printf(" Change a user's password using an admin account\n");
48 d_printf(" (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
49 d_printf("changetrustpw\n");
50 d_printf(" Change the trust account password of this machine in the AD tree\n");
51 d_printf("printer [info | publish | remove] <printername> <servername>\n");
52 d_printf(" Lookup, add, or remove directory entry for a printer\n");
53 d_printf("{search,dn,sid}\n");
54 d_printf(" Issue LDAP search queries using a general filter, by DN, or by SID\n");
55 d_printf("keytab\n");
56 d_printf(" Manage a local keytab file based on the machine account in AD\n");
57 d_printf("dns\n");
58 d_printf(" Issue a dynamic DNS update request the server's hostname\n");
59 d_printf(" (using the machine credentials)\n");
61 return -1;
64 /* when we do not have sufficient input parameters to contact a remote domain
65 * we always fall back to our own realm - Guenther*/
67 static const char *assume_own_realm(void)
69 if (!opt_host && strequal(lp_workgroup(), opt_target_workgroup)) {
70 return lp_realm();
73 return NULL;
77 do a cldap netlogon query
79 static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
81 char addr[INET6_ADDRSTRLEN];
82 struct nbt_cldap_netlogon_5 reply;
84 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
85 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
86 d_fprintf(stderr, "CLDAP query failed!\n");
87 return -1;
90 d_printf("Information for Domain Controller: %s\n\n",
91 addr);
93 d_printf("Response Type: ");
94 switch (reply.type) {
95 case SAMLOGON_AD_UNK_R:
96 d_printf("SAMLOGON\n");
97 break;
98 case SAMLOGON_AD_R:
99 d_printf("SAMLOGON_USER\n");
100 break;
101 default:
102 d_printf("0x%x\n", reply.type);
103 break;
106 d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), reply.domain_uuid));
108 d_printf("Flags:\n"
109 "\tIs a PDC: %s\n"
110 "\tIs a GC of the forest: %s\n"
111 "\tIs an LDAP server: %s\n"
112 "\tSupports DS: %s\n"
113 "\tIs running a KDC: %s\n"
114 "\tIs running time services: %s\n"
115 "\tIs the closest DC: %s\n"
116 "\tIs writable: %s\n"
117 "\tHas a hardware clock: %s\n"
118 "\tIs a non-domain NC serviced by LDAP server: %s\n",
119 (reply.server_type & NBT_SERVER_PDC) ? "yes" : "no",
120 (reply.server_type & NBT_SERVER_GC) ? "yes" : "no",
121 (reply.server_type & NBT_SERVER_LDAP) ? "yes" : "no",
122 (reply.server_type & NBT_SERVER_DS) ? "yes" : "no",
123 (reply.server_type & NBT_SERVER_KDC) ? "yes" : "no",
124 (reply.server_type & NBT_SERVER_TIMESERV) ? "yes" : "no",
125 (reply.server_type & NBT_SERVER_CLOSEST) ? "yes" : "no",
126 (reply.server_type & NBT_SERVER_WRITABLE) ? "yes" : "no",
127 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? "yes" : "no",
128 (reply.server_type & DS_SERVER_NDNC) ? "yes" : "no");
130 printf("Forest:\t\t\t%s\n", reply.forest);
131 printf("Domain:\t\t\t%s\n", reply.dns_domain);
132 printf("Domain Controller:\t%s\n", reply.pdc_dns_name);
134 printf("Pre-Win2k Domain:\t%s\n", reply.domain);
135 printf("Pre-Win2k Hostname:\t%s\n", reply.pdc_name);
137 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
139 printf("Server Site Name :\t\t%s\n", reply.server_site);
140 printf("Client Site Name :\t\t%s\n", reply.client_site);
142 d_printf("NT Version: %d\n", reply.nt_version);
143 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
144 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
146 return 0;
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)
155 ADS_STRUCT *ads;
157 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
158 d_fprintf(stderr, "Didn't find the cldap server!\n");
159 return -1;
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)
174 ADS_STRUCT *ads;
175 char addr[INET6_ADDRSTRLEN];
177 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
178 d_fprintf(stderr, "Didn't find the ldap server!\n");
179 return -1;
182 if (!ads || !ads->config.realm) {
183 d_fprintf(stderr, "Didn't find the ldap server!\n");
184 return -1;
187 /* Try to set the server's current time since we didn't do a full
188 TCP LDAP session initially */
190 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
191 d_fprintf( stderr, "Failed to get server's current time!\n");
194 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
196 d_printf("LDAP server: %s\n", addr);
197 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
198 d_printf("Realm: %s\n", ads->config.realm);
199 d_printf("Bind Path: %s\n", ads->config.bind_path);
200 d_printf("LDAP port: %d\n", ads->ldap.port);
201 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
203 d_printf("KDC server: %s\n", ads->auth.kdc_server );
204 d_printf("Server time offset: %d\n", ads->auth.time_offset );
206 return 0;
209 static void use_in_memory_ccache(void) {
210 /* Use in-memory credentials cache so we do not interfere with
211 * existing credentials */
212 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
215 static ADS_STATUS ads_startup_int(bool only_own_domain, uint32 auth_flags, ADS_STRUCT **ads_ret)
217 ADS_STRUCT *ads = NULL;
218 ADS_STATUS status;
219 bool need_password = False;
220 bool second_time = False;
221 char *cp;
222 const char *realm = NULL;
223 bool tried_closest_dc = False;
225 /* lp_realm() should be handled by a command line param,
226 However, the join requires that realm be set in smb.conf
227 and compares our realm with the remote server's so this is
228 ok until someone needs more flexibility */
230 *ads_ret = NULL;
232 retry_connect:
233 if (only_own_domain) {
234 realm = lp_realm();
235 } else {
236 realm = assume_own_realm();
239 ads = ads_init(realm, opt_target_workgroup, opt_host);
241 if (!opt_user_name) {
242 opt_user_name = "administrator";
245 if (opt_user_specified) {
246 need_password = True;
249 retry:
250 if (!opt_password && need_password && !opt_machine_pass) {
251 opt_password = net_prompt_pass(opt_user_name);
252 if (!opt_password) {
253 ads_destroy(&ads);
254 return ADS_ERROR(LDAP_NO_MEMORY);
258 if (opt_password) {
259 use_in_memory_ccache();
260 SAFE_FREE(ads->auth.password);
261 ads->auth.password = smb_xstrdup(opt_password);
264 ads->auth.flags |= auth_flags;
265 SAFE_FREE(ads->auth.user_name);
266 ads->auth.user_name = smb_xstrdup(opt_user_name);
269 * If the username is of the form "name@realm",
270 * extract the realm and convert to upper case.
271 * This is only used to establish the connection.
273 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
274 *cp++ = '\0';
275 SAFE_FREE(ads->auth.realm);
276 ads->auth.realm = smb_xstrdup(cp);
277 strupper_m(ads->auth.realm);
280 status = ads_connect(ads);
282 if (!ADS_ERR_OK(status)) {
284 if (NT_STATUS_EQUAL(ads_ntstatus(status),
285 NT_STATUS_NO_LOGON_SERVERS)) {
286 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
287 ads_destroy(&ads);
288 return status;
291 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
292 need_password = True;
293 second_time = True;
294 goto retry;
295 } else {
296 ads_destroy(&ads);
297 return status;
301 /* when contacting our own domain, make sure we use the closest DC.
302 * This is done by reconnecting to ADS because only the first call to
303 * ads_connect will give us our own sitename */
305 if ((only_own_domain || !opt_host) && !tried_closest_dc) {
307 tried_closest_dc = True; /* avoid loop */
309 if (!ads_closest_dc(ads)) {
311 namecache_delete(ads->server.realm, 0x1C);
312 namecache_delete(ads->server.workgroup, 0x1C);
314 ads_destroy(&ads);
315 ads = NULL;
317 goto retry_connect;
321 *ads_ret = ads;
322 return status;
325 ADS_STATUS ads_startup(bool only_own_domain, ADS_STRUCT **ads)
327 return ads_startup_int(only_own_domain, 0, ads);
330 ADS_STATUS ads_startup_nobind(bool only_own_domain, ADS_STRUCT **ads)
332 return ads_startup_int(only_own_domain, ADS_AUTH_NO_BIND, ads);
336 Check to see if connection can be made via ads.
337 ads_startup() stores the password in opt_password if it needs to so
338 that rpc or rap can use it without re-prompting.
340 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
342 ADS_STRUCT *ads;
343 ADS_STATUS status;
345 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
346 return -1;
349 ads->auth.flags |= ADS_AUTH_NO_BIND;
351 status = ads_connect(ads);
352 if ( !ADS_ERR_OK(status) ) {
353 return -1;
356 ads_destroy(&ads);
357 return 0;
360 int net_ads_check_our_domain(void)
362 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
365 int net_ads_check(void)
367 return net_ads_check_int(NULL, opt_workgroup, opt_host);
371 determine the netbios workgroup name for a domain
373 static int net_ads_workgroup(int argc, const char **argv)
375 ADS_STRUCT *ads;
376 char addr[INET6_ADDRSTRLEN];
377 struct nbt_cldap_netlogon_5 reply;
379 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
380 d_fprintf(stderr, "Didn't find the cldap server!\n");
381 return -1;
384 if (!ads->config.realm) {
385 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
386 ads->ldap.port = 389;
389 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
390 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
391 d_fprintf(stderr, "CLDAP query failed!\n");
392 return -1;
395 d_printf("Workgroup: %s\n", reply.domain);
397 ads_destroy(&ads);
399 return 0;
404 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
406 char **disp_fields = (char **) data_area;
408 if (!field) { /* must be end of record */
409 if (disp_fields[0]) {
410 if (!strchr_m(disp_fields[0], '$')) {
411 if (disp_fields[1])
412 d_printf("%-21.21s %s\n",
413 disp_fields[0], disp_fields[1]);
414 else
415 d_printf("%s\n", disp_fields[0]);
418 SAFE_FREE(disp_fields[0]);
419 SAFE_FREE(disp_fields[1]);
420 return True;
422 if (!values) /* must be new field, indicate string field */
423 return True;
424 if (StrCaseCmp(field, "sAMAccountName") == 0) {
425 disp_fields[0] = SMB_STRDUP((char *) values[0]);
427 if (StrCaseCmp(field, "description") == 0)
428 disp_fields[1] = SMB_STRDUP((char *) values[0]);
429 return True;
432 static int net_ads_user_usage(int argc, const char **argv)
434 return net_help_user(argc, argv);
437 static int ads_user_add(int argc, const char **argv)
439 ADS_STRUCT *ads;
440 ADS_STATUS status;
441 char *upn, *userdn;
442 LDAPMessage *res=NULL;
443 int rc = -1;
444 char *ou_str = NULL;
446 if (argc < 1) return net_ads_user_usage(argc, argv);
448 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
449 return -1;
452 status = ads_find_user_acct(ads, &res, argv[0]);
454 if (!ADS_ERR_OK(status)) {
455 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
456 goto done;
459 if (ads_count_replies(ads, res)) {
460 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
461 goto done;
464 if (opt_container) {
465 ou_str = SMB_STRDUP(opt_container);
466 } else {
467 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
470 status = ads_add_user_acct(ads, argv[0], ou_str, opt_comment);
472 if (!ADS_ERR_OK(status)) {
473 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
474 ads_errstr(status));
475 goto done;
478 /* if no password is to be set, we're done */
479 if (argc == 1) {
480 d_printf("User %s added\n", argv[0]);
481 rc = 0;
482 goto done;
485 /* try setting the password */
486 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
487 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
488 ads->auth.time_offset);
489 safe_free(upn);
490 if (ADS_ERR_OK(status)) {
491 d_printf("User %s added\n", argv[0]);
492 rc = 0;
493 goto done;
496 /* password didn't set, delete account */
497 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
498 argv[0], ads_errstr(status));
499 ads_msgfree(ads, res);
500 status=ads_find_user_acct(ads, &res, argv[0]);
501 if (ADS_ERR_OK(status)) {
502 userdn = ads_get_dn(ads, res);
503 ads_del_dn(ads, userdn);
504 ads_memfree(ads, userdn);
507 done:
508 if (res)
509 ads_msgfree(ads, res);
510 ads_destroy(&ads);
511 SAFE_FREE(ou_str);
512 return rc;
515 static int ads_user_info(int argc, const char **argv)
517 ADS_STRUCT *ads;
518 ADS_STATUS rc;
519 LDAPMessage *res;
520 const char *attrs[] = {"memberOf", NULL};
521 char *searchstring=NULL;
522 char **grouplist;
523 char *escaped_user;
525 if (argc < 1) {
526 return net_ads_user_usage(argc, argv);
529 escaped_user = escape_ldap_string_alloc(argv[0]);
531 if (!escaped_user) {
532 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
533 return -1;
536 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
537 SAFE_FREE(escaped_user);
538 return -1;
541 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
542 rc = ads_search(ads, &res, searchstring, attrs);
543 safe_free(searchstring);
545 if (!ADS_ERR_OK(rc)) {
546 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
547 ads_destroy(&ads);
548 SAFE_FREE(escaped_user);
549 return -1;
552 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
553 (LDAPMessage *)res, "memberOf");
555 if (grouplist) {
556 int i;
557 char **groupname;
558 for (i=0;grouplist[i];i++) {
559 groupname = ldap_explode_dn(grouplist[i], 1);
560 d_printf("%s\n", groupname[0]);
561 ldap_value_free(groupname);
563 ldap_value_free(grouplist);
566 ads_msgfree(ads, res);
567 ads_destroy(&ads);
568 SAFE_FREE(escaped_user);
569 return 0;
572 static int ads_user_delete(int argc, const char **argv)
574 ADS_STRUCT *ads;
575 ADS_STATUS rc;
576 LDAPMessage *res = NULL;
577 char *userdn;
579 if (argc < 1) {
580 return net_ads_user_usage(argc, argv);
583 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
584 return -1;
587 rc = ads_find_user_acct(ads, &res, argv[0]);
588 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
589 d_printf("User %s does not exist.\n", argv[0]);
590 ads_msgfree(ads, res);
591 ads_destroy(&ads);
592 return -1;
594 userdn = ads_get_dn(ads, res);
595 ads_msgfree(ads, res);
596 rc = ads_del_dn(ads, userdn);
597 ads_memfree(ads, userdn);
598 if (ADS_ERR_OK(rc)) {
599 d_printf("User %s deleted\n", argv[0]);
600 ads_destroy(&ads);
601 return 0;
603 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
604 ads_errstr(rc));
605 ads_destroy(&ads);
606 return -1;
609 int net_ads_user(int argc, const char **argv)
611 struct functable func[] = {
612 {"ADD", ads_user_add},
613 {"INFO", ads_user_info},
614 {"DELETE", ads_user_delete},
615 {NULL, NULL}
617 ADS_STRUCT *ads;
618 ADS_STATUS rc;
619 const char *shortattrs[] = {"sAMAccountName", NULL};
620 const char *longattrs[] = {"sAMAccountName", "description", NULL};
621 char *disp_fields[2] = {NULL, NULL};
623 if (argc == 0) {
624 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
625 return -1;
628 if (opt_long_list_entries)
629 d_printf("\nUser name Comment"\
630 "\n-----------------------------\n");
632 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
633 LDAP_SCOPE_SUBTREE,
634 "(objectCategory=user)",
635 opt_long_list_entries ? longattrs :
636 shortattrs, usergrp_display,
637 disp_fields);
638 ads_destroy(&ads);
639 return ADS_ERR_OK(rc) ? 0 : -1;
642 return net_run_function(argc, argv, func, net_ads_user_usage);
645 static int net_ads_group_usage(int argc, const char **argv)
647 return net_help_group(argc, argv);
650 static int ads_group_add(int argc, const char **argv)
652 ADS_STRUCT *ads;
653 ADS_STATUS status;
654 LDAPMessage *res=NULL;
655 int rc = -1;
656 char *ou_str = NULL;
658 if (argc < 1) {
659 return net_ads_group_usage(argc, argv);
662 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
663 return -1;
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));
670 goto done;
673 if (ads_count_replies(ads, res)) {
674 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
675 goto done;
678 if (opt_container) {
679 ou_str = SMB_STRDUP(opt_container);
680 } else {
681 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
684 status = ads_add_group_acct(ads, argv[0], ou_str, opt_comment);
686 if (ADS_ERR_OK(status)) {
687 d_printf("Group %s added\n", argv[0]);
688 rc = 0;
689 } else {
690 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
691 ads_errstr(status));
694 done:
695 if (res)
696 ads_msgfree(ads, res);
697 ads_destroy(&ads);
698 SAFE_FREE(ou_str);
699 return rc;
702 static int ads_group_delete(int argc, const char **argv)
704 ADS_STRUCT *ads;
705 ADS_STATUS rc;
706 LDAPMessage *res = NULL;
707 char *groupdn;
709 if (argc < 1) {
710 return net_ads_group_usage(argc, argv);
713 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
714 return -1;
717 rc = ads_find_user_acct(ads, &res, argv[0]);
718 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
719 d_printf("Group %s does not exist.\n", argv[0]);
720 ads_msgfree(ads, res);
721 ads_destroy(&ads);
722 return -1;
724 groupdn = ads_get_dn(ads, res);
725 ads_msgfree(ads, res);
726 rc = ads_del_dn(ads, groupdn);
727 ads_memfree(ads, groupdn);
728 if (ADS_ERR_OK(rc)) {
729 d_printf("Group %s deleted\n", argv[0]);
730 ads_destroy(&ads);
731 return 0;
733 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
734 ads_errstr(rc));
735 ads_destroy(&ads);
736 return -1;
739 int net_ads_group(int argc, const char **argv)
741 struct functable func[] = {
742 {"ADD", ads_group_add},
743 {"DELETE", ads_group_delete},
744 {NULL, NULL}
746 ADS_STRUCT *ads;
747 ADS_STATUS rc;
748 const char *shortattrs[] = {"sAMAccountName", NULL};
749 const char *longattrs[] = {"sAMAccountName", "description", NULL};
750 char *disp_fields[2] = {NULL, NULL};
752 if (argc == 0) {
753 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
754 return -1;
757 if (opt_long_list_entries)
758 d_printf("\nGroup name Comment"\
759 "\n-----------------------------\n");
760 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
761 LDAP_SCOPE_SUBTREE,
762 "(objectCategory=group)",
763 opt_long_list_entries ? longattrs :
764 shortattrs, usergrp_display,
765 disp_fields);
767 ads_destroy(&ads);
768 return ADS_ERR_OK(rc) ? 0 : -1;
770 return net_run_function(argc, argv, func, net_ads_group_usage);
773 static int net_ads_status(int argc, const char **argv)
775 ADS_STRUCT *ads;
776 ADS_STATUS rc;
777 LDAPMessage *res;
779 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
780 return -1;
783 rc = ads_find_machine_acct(ads, &res, global_myname());
784 if (!ADS_ERR_OK(rc)) {
785 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
786 ads_destroy(&ads);
787 return -1;
790 if (ads_count_replies(ads, res) == 0) {
791 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
792 ads_destroy(&ads);
793 return -1;
796 ads_dump(ads, res);
797 ads_destroy(&ads);
798 return 0;
801 /*******************************************************************
802 Leave an AD domain. Windows XP disables the machine account.
803 We'll try the same. The old code would do an LDAP delete.
804 That only worked using the machine creds because added the machine
805 with full control to the computer object's ACL.
806 *******************************************************************/
808 static int net_ads_leave(int argc, const char **argv)
810 TALLOC_CTX *ctx;
811 struct libnet_UnjoinCtx *r = NULL;
812 WERROR werr;
814 if (!*lp_realm()) {
815 d_fprintf(stderr, "No realm set, are we joined ?\n");
816 return -1;
819 if (!(ctx = talloc_init("net_ads_leave"))) {
820 d_fprintf(stderr, "Could not initialise talloc context.\n");
821 return -1;
824 use_in_memory_ccache();
826 werr = libnet_init_UnjoinCtx(ctx, &r);
827 if (!W_ERROR_IS_OK(werr)) {
828 d_fprintf(stderr, "Could not initialise unjoin context.\n");
829 return -1;
832 r->in.debug = true;
833 r->in.dc_name = opt_host;
834 r->in.domain_name = lp_realm();
835 r->in.admin_account = opt_user_name;
836 r->in.admin_password = net_prompt_pass(opt_user_name);
837 r->in.modify_config = lp_config_backend_is_registry();
838 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
839 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
841 werr = libnet_Unjoin(ctx, r);
842 if (!W_ERROR_IS_OK(werr)) {
843 d_printf("Failed to leave domain: %s\n",
844 r->out.error_string ? r->out.error_string :
845 get_friendly_werror_msg(werr));
846 goto done;
849 if (W_ERROR_IS_OK(werr)) {
850 d_printf("Deleted account for '%s' in realm '%s'\n",
851 r->in.machine_name, r->out.dns_domain_name);
852 goto done;
855 /* We couldn't delete it - see if the disable succeeded. */
856 if (r->out.disabled_machine_account) {
857 d_printf("Disabled account for '%s' in realm '%s'\n",
858 r->in.machine_name, r->out.dns_domain_name);
859 werr = WERR_OK;
860 goto done;
863 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
864 r->in.machine_name, r->out.dns_domain_name);
866 done:
867 TALLOC_FREE(r);
868 TALLOC_FREE(ctx);
870 if (W_ERROR_IS_OK(werr)) {
871 return 0;
874 return -1;
877 static NTSTATUS net_ads_join_ok(void)
879 ADS_STRUCT *ads = NULL;
880 ADS_STATUS status;
882 if (!secrets_init()) {
883 DEBUG(1,("Failed to initialise secrets database\n"));
884 return NT_STATUS_ACCESS_DENIED;
887 net_use_krb_machine_account();
889 status = ads_startup(True, &ads);
890 if (!ADS_ERR_OK(status)) {
891 return ads_ntstatus(status);
894 ads_destroy(&ads);
895 return NT_STATUS_OK;
899 check that an existing join is OK
901 int net_ads_testjoin(int argc, const char **argv)
903 NTSTATUS status;
904 use_in_memory_ccache();
906 /* Display success or failure */
907 status = net_ads_join_ok();
908 if (!NT_STATUS_IS_OK(status)) {
909 fprintf(stderr,"Join to domain is not valid: %s\n",
910 get_friendly_nt_error_msg(status));
911 return -1;
914 printf("Join is OK\n");
915 return 0;
918 /*******************************************************************
919 Simple configu checks before beginning the join
920 ********************************************************************/
922 static WERROR check_ads_config( void )
924 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
925 d_printf("Host is not configured as a member server.\n");
926 return WERR_INVALID_DOMAIN_ROLE;
929 if (strlen(global_myname()) > 15) {
930 d_printf("Our netbios name can be at most 15 chars long, "
931 "\"%s\" is %u chars long\n", global_myname(),
932 (unsigned int)strlen(global_myname()));
933 return WERR_INVALID_COMPUTER_NAME;
936 if ( lp_security() == SEC_ADS && !*lp_realm()) {
937 d_fprintf(stderr, "realm must be set in in %s for ADS "
938 "join to succeed.\n", get_dyn_CONFIGFILE());
939 return WERR_INVALID_PARAM;
942 return WERR_OK;
945 /*******************************************************************
946 Send a DNS update request
947 *******************************************************************/
949 #if defined(WITH_DNS_UPDATES)
950 #include "dns.h"
951 DNS_ERROR DoDNSUpdate(char *pszServerName,
952 const char *pszDomainName, const char *pszHostName,
953 const struct sockaddr_storage *sslist,
954 size_t num_addrs );
956 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
957 const char *machine_name,
958 const struct sockaddr_storage *addrs,
959 int num_addrs)
961 struct dns_rr_ns *nameservers = NULL;
962 int ns_count = 0;
963 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
964 DNS_ERROR dns_err;
965 fstring dns_server;
966 const char *dnsdomain = NULL;
967 char *root_domain = NULL;
969 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
970 d_printf("No DNS domain configured for %s. "
971 "Unable to perform DNS Update.\n", machine_name);
972 status = NT_STATUS_INVALID_PARAMETER;
973 goto done;
975 dnsdomain++;
977 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
978 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
979 /* Child domains often do not have NS records. Look
980 for the NS record for the forest root domain
981 (rootDomainNamingContext in therootDSE) */
983 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
984 LDAPMessage *msg = NULL;
985 char *root_dn;
986 ADS_STATUS ads_status;
988 if ( !ads->ldap.ld ) {
989 ads_status = ads_connect( ads );
990 if ( !ADS_ERR_OK(ads_status) ) {
991 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
992 goto done;
996 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
997 "(objectclass=*)", rootname_attrs, &msg);
998 if (!ADS_ERR_OK(ads_status)) {
999 goto done;
1002 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1003 if ( !root_dn ) {
1004 ads_msgfree( ads, msg );
1005 goto done;
1008 root_domain = ads_build_domain( root_dn );
1010 /* cleanup */
1011 ads_msgfree( ads, msg );
1013 /* try again for NS servers */
1015 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1017 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1018 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1019 "realm\n", ads->config.realm));
1020 goto done;
1023 dnsdomain = root_domain;
1027 /* Now perform the dns update - we'll try non-secure and if we fail,
1028 we'll follow it up with a secure update */
1030 fstrcpy( dns_server, nameservers[0].hostname );
1032 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1033 if (!ERR_DNS_IS_OK(dns_err)) {
1034 status = NT_STATUS_UNSUCCESSFUL;
1037 done:
1039 SAFE_FREE( root_domain );
1041 return status;
1044 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1046 int num_addrs;
1047 struct sockaddr_storage *iplist = NULL;
1048 fstring machine_name;
1049 NTSTATUS status;
1051 name_to_fqdn( machine_name, global_myname() );
1052 strlower_m( machine_name );
1054 /* Get our ip address (not the 127.0.0.x address but a real ip
1055 * address) */
1057 num_addrs = get_my_ip_address( &iplist );
1058 if ( num_addrs <= 0 ) {
1059 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1060 "addresses!\n"));
1061 return NT_STATUS_INVALID_PARAMETER;
1064 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1065 iplist, num_addrs);
1066 SAFE_FREE( iplist );
1067 return status;
1069 #endif
1072 /*******************************************************************
1073 ********************************************************************/
1075 static int net_ads_join_usage(int argc, const char **argv)
1077 d_printf("net ads join [options]\n");
1078 d_printf("Valid options:\n");
1079 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1080 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1081 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1082 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1083 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1084 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1085 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1086 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1087 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1088 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1089 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1090 d_printf(" the two other attributes.\n");
1092 return -1;
1095 /*******************************************************************
1096 ********************************************************************/
1098 int net_ads_join(int argc, const char **argv)
1100 TALLOC_CTX *ctx = NULL;
1101 struct libnet_JoinCtx *r = NULL;
1102 const char *domain = lp_realm();
1103 WERROR werr = WERR_SETUP_NOT_JOINED;
1104 bool createupn = False;
1105 const char *machineupn = NULL;
1106 const char *create_in_ou = NULL;
1107 int i;
1108 const char *os_name = NULL;
1109 const char *os_version = NULL;
1110 bool modify_config = lp_config_backend_is_registry();
1112 if (!modify_config) {
1114 werr = check_ads_config();
1115 if (!W_ERROR_IS_OK(werr)) {
1116 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1117 goto fail;
1121 if (!(ctx = talloc_init("net_ads_join"))) {
1122 d_fprintf(stderr, "Could not initialise talloc context.\n");
1123 werr = WERR_NOMEM;
1124 goto fail;
1127 use_in_memory_ccache();
1129 werr = libnet_init_JoinCtx(ctx, &r);
1130 if (!W_ERROR_IS_OK(werr)) {
1131 goto fail;
1134 /* process additional command line args */
1136 for ( i=0; i<argc; i++ ) {
1137 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1138 createupn = True;
1139 machineupn = get_string_param(argv[i]);
1141 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1142 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1143 d_fprintf(stderr, "Please supply a valid OU path.\n");
1144 werr = WERR_INVALID_PARAM;
1145 goto fail;
1148 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1149 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1150 d_fprintf(stderr, "Please supply a operating system name.\n");
1151 werr = WERR_INVALID_PARAM;
1152 goto fail;
1155 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1156 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1157 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1158 werr = WERR_INVALID_PARAM;
1159 goto fail;
1162 else {
1163 domain = argv[i];
1167 if (!*domain) {
1168 d_fprintf(stderr, "Please supply a valid domain name\n");
1169 werr = WERR_INVALID_PARAM;
1170 goto fail;
1173 /* Do the domain join here */
1175 r->in.domain_name = domain;
1176 r->in.create_upn = createupn;
1177 r->in.upn = machineupn;
1178 r->in.account_ou = create_in_ou;
1179 r->in.os_name = os_name;
1180 r->in.os_version = os_version;
1181 r->in.dc_name = opt_host;
1182 r->in.admin_account = opt_user_name;
1183 r->in.admin_password = net_prompt_pass(opt_user_name);
1184 r->in.debug = true;
1185 r->in.modify_config = modify_config;
1186 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1187 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1188 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1190 werr = libnet_Join(ctx, r);
1191 if (!W_ERROR_IS_OK(werr)) {
1192 goto fail;
1195 /* Check the short name of the domain */
1197 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1198 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1199 d_printf("domain name obtained from the server.\n");
1200 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1201 d_printf("You should set \"workgroup = %s\" in %s.\n",
1202 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1205 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1207 if (r->out.dns_domain_name) {
1208 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1209 r->out.dns_domain_name);
1210 } else {
1211 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1212 r->out.netbios_domain_name);
1215 #if defined(WITH_DNS_UPDATES)
1216 if (r->out.domain_is_ad) {
1217 /* We enter this block with user creds */
1218 ADS_STRUCT *ads_dns = NULL;
1220 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1221 /* kinit with the machine password */
1223 use_in_memory_ccache();
1224 asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1225 ads_dns->auth.password = secrets_fetch_machine_password(
1226 r->out.netbios_domain_name, NULL, NULL );
1227 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1228 strupper_m(ads_dns->auth.realm );
1229 ads_kinit_password( ads_dns );
1232 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1233 d_fprintf( stderr, "DNS update failed!\n" );
1236 /* exit from this block using machine creds */
1237 ads_destroy(&ads_dns);
1239 #endif
1240 TALLOC_FREE(r);
1241 TALLOC_FREE( ctx );
1243 return 0;
1245 fail:
1246 /* issue an overall failure message at the end. */
1247 d_printf("Failed to join domain: %s\n",
1248 r && r->out.error_string ? r->out.error_string :
1249 get_friendly_werror_msg(werr));
1250 TALLOC_FREE( ctx );
1252 return -1;
1255 /*******************************************************************
1256 ********************************************************************/
1258 static int net_ads_dns_usage(int argc, const char **argv)
1260 #if defined(WITH_DNS_UPDATES)
1261 d_printf("net ads dns <command>\n");
1262 d_printf("Valid commands:\n");
1263 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1265 return 0;
1266 #else
1267 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1268 return -1;
1269 #endif
1272 /*******************************************************************
1273 ********************************************************************/
1275 static int net_ads_dns_register(int argc, const char **argv)
1277 #if defined(WITH_DNS_UPDATES)
1278 ADS_STRUCT *ads;
1279 ADS_STATUS status;
1280 TALLOC_CTX *ctx;
1282 #ifdef DEVELOPER
1283 talloc_enable_leak_report();
1284 #endif
1286 if (argc > 0) {
1287 d_fprintf(stderr, "net ads dns register\n");
1288 return -1;
1291 if (!(ctx = talloc_init("net_ads_dns"))) {
1292 d_fprintf(stderr, "Could not initialise talloc context\n");
1293 return -1;
1296 status = ads_startup(True, &ads);
1297 if ( !ADS_ERR_OK(status) ) {
1298 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1299 TALLOC_FREE(ctx);
1300 return -1;
1303 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1304 d_fprintf( stderr, "DNS update failed!\n" );
1305 ads_destroy( &ads );
1306 TALLOC_FREE( ctx );
1307 return -1;
1310 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1312 ads_destroy(&ads);
1313 TALLOC_FREE( ctx );
1315 return 0;
1316 #else
1317 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1318 return -1;
1319 #endif
1322 #if defined(WITH_DNS_UPDATES)
1323 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1324 #endif
1326 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1328 #if defined(WITH_DNS_UPDATES)
1329 DNS_ERROR err;
1331 #ifdef DEVELOPER
1332 talloc_enable_leak_report();
1333 #endif
1335 if (argc != 2) {
1336 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1337 "<name>\n");
1338 return -1;
1341 err = do_gethostbyname(argv[0], argv[1]);
1343 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1344 #endif
1345 return 0;
1348 static int net_ads_dns(int argc, const char *argv[])
1350 struct functable func[] = {
1351 {"REGISTER", net_ads_dns_register},
1352 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1353 {NULL, NULL}
1356 return net_run_function(argc, argv, func, net_ads_dns_usage);
1359 /*******************************************************************
1360 ********************************************************************/
1362 int net_ads_printer_usage(int argc, const char **argv)
1364 d_printf(
1365 "\nnet ads printer search <printer>"
1366 "\n\tsearch for a printer in the directory\n"
1367 "\nnet ads printer info <printer> <server>"
1368 "\n\tlookup info in directory for printer on server"
1369 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1370 "\nnet ads printer publish <printername>"
1371 "\n\tpublish printer in directory"
1372 "\n\t(note: printer name is required)\n"
1373 "\nnet ads printer remove <printername>"
1374 "\n\tremove printer from directory"
1375 "\n\t(note: printer name is required)\n");
1376 return -1;
1379 /*******************************************************************
1380 ********************************************************************/
1382 static int net_ads_printer_search(int argc, const char **argv)
1384 ADS_STRUCT *ads;
1385 ADS_STATUS rc;
1386 LDAPMessage *res = NULL;
1388 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1389 return -1;
1392 rc = ads_find_printers(ads, &res);
1394 if (!ADS_ERR_OK(rc)) {
1395 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1396 ads_msgfree(ads, res);
1397 ads_destroy(&ads);
1398 return -1;
1401 if (ads_count_replies(ads, res) == 0) {
1402 d_fprintf(stderr, "No results found\n");
1403 ads_msgfree(ads, res);
1404 ads_destroy(&ads);
1405 return -1;
1408 ads_dump(ads, res);
1409 ads_msgfree(ads, res);
1410 ads_destroy(&ads);
1411 return 0;
1414 static int net_ads_printer_info(int argc, const char **argv)
1416 ADS_STRUCT *ads;
1417 ADS_STATUS rc;
1418 const char *servername, *printername;
1419 LDAPMessage *res = NULL;
1421 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1422 return -1;
1425 if (argc > 0) {
1426 printername = argv[0];
1427 } else {
1428 printername = "*";
1431 if (argc > 1) {
1432 servername = argv[1];
1433 } else {
1434 servername = global_myname();
1437 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1439 if (!ADS_ERR_OK(rc)) {
1440 d_fprintf(stderr, "Server '%s' not found: %s\n",
1441 servername, ads_errstr(rc));
1442 ads_msgfree(ads, res);
1443 ads_destroy(&ads);
1444 return -1;
1447 if (ads_count_replies(ads, res) == 0) {
1448 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1449 ads_msgfree(ads, res);
1450 ads_destroy(&ads);
1451 return -1;
1454 ads_dump(ads, res);
1455 ads_msgfree(ads, res);
1456 ads_destroy(&ads);
1458 return 0;
1461 static int net_ads_printer_publish(int argc, const char **argv)
1463 ADS_STRUCT *ads;
1464 ADS_STATUS rc;
1465 const char *servername, *printername;
1466 struct cli_state *cli;
1467 struct rpc_pipe_client *pipe_hnd;
1468 struct sockaddr_storage server_ss;
1469 NTSTATUS nt_status;
1470 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1471 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1472 char *prt_dn, *srv_dn, **srv_cn;
1473 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1474 LDAPMessage *res = NULL;
1476 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1477 talloc_destroy(mem_ctx);
1478 return -1;
1481 if (argc < 1) {
1482 talloc_destroy(mem_ctx);
1483 return net_ads_printer_usage(argc, argv);
1486 printername = argv[0];
1488 if (argc == 2) {
1489 servername = argv[1];
1490 } else {
1491 servername = global_myname();
1494 /* Get printer data from SPOOLSS */
1496 resolve_name(servername, &server_ss, 0x20);
1498 nt_status = cli_full_connection(&cli, global_myname(), servername,
1499 &server_ss, 0,
1500 "IPC$", "IPC",
1501 opt_user_name, opt_workgroup,
1502 opt_password ? opt_password : "",
1503 CLI_FULL_CONNECTION_USE_KERBEROS,
1504 Undefined, NULL);
1506 if (NT_STATUS_IS_ERR(nt_status)) {
1507 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1508 "for %s\n", servername, printername);
1509 ads_destroy(&ads);
1510 talloc_destroy(mem_ctx);
1511 return -1;
1514 /* Publish on AD server */
1516 ads_find_machine_acct(ads, &res, servername);
1518 if (ads_count_replies(ads, res) == 0) {
1519 d_fprintf(stderr, "Could not find machine account for server %s\n",
1520 servername);
1521 ads_destroy(&ads);
1522 talloc_destroy(mem_ctx);
1523 return -1;
1526 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1527 srv_cn = ldap_explode_dn(srv_dn, 1);
1529 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1530 printername_escaped = escape_rdn_val_string_alloc(printername);
1531 if (!srv_cn_escaped || !printername_escaped) {
1532 SAFE_FREE(srv_cn_escaped);
1533 SAFE_FREE(printername_escaped);
1534 d_fprintf(stderr, "Internal error, out of memory!");
1535 ads_destroy(&ads);
1536 talloc_destroy(mem_ctx);
1537 return -1;
1540 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1542 SAFE_FREE(srv_cn_escaped);
1543 SAFE_FREE(printername_escaped);
1545 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1546 if (!pipe_hnd) {
1547 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1548 servername);
1549 SAFE_FREE(prt_dn);
1550 ads_destroy(&ads);
1551 talloc_destroy(mem_ctx);
1552 return -1;
1555 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1556 printername))) {
1557 SAFE_FREE(prt_dn);
1558 ads_destroy(&ads);
1559 talloc_destroy(mem_ctx);
1560 return -1;
1563 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1564 if (!ADS_ERR_OK(rc)) {
1565 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1566 SAFE_FREE(prt_dn);
1567 ads_destroy(&ads);
1568 talloc_destroy(mem_ctx);
1569 return -1;
1572 d_printf("published printer\n");
1573 SAFE_FREE(prt_dn);
1574 ads_destroy(&ads);
1575 talloc_destroy(mem_ctx);
1577 return 0;
1580 static int net_ads_printer_remove(int argc, const char **argv)
1582 ADS_STRUCT *ads;
1583 ADS_STATUS rc;
1584 const char *servername;
1585 char *prt_dn;
1586 LDAPMessage *res = NULL;
1588 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1589 return -1;
1592 if (argc < 1) {
1593 return net_ads_printer_usage(argc, argv);
1596 if (argc > 1) {
1597 servername = argv[1];
1598 } else {
1599 servername = global_myname();
1602 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1604 if (!ADS_ERR_OK(rc)) {
1605 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1606 ads_msgfree(ads, res);
1607 ads_destroy(&ads);
1608 return -1;
1611 if (ads_count_replies(ads, res) == 0) {
1612 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1613 ads_msgfree(ads, res);
1614 ads_destroy(&ads);
1615 return -1;
1618 prt_dn = ads_get_dn(ads, res);
1619 ads_msgfree(ads, res);
1620 rc = ads_del_dn(ads, prt_dn);
1621 ads_memfree(ads, prt_dn);
1623 if (!ADS_ERR_OK(rc)) {
1624 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1625 ads_destroy(&ads);
1626 return -1;
1629 ads_destroy(&ads);
1630 return 0;
1633 static int net_ads_printer(int argc, const char **argv)
1635 struct functable func[] = {
1636 {"SEARCH", net_ads_printer_search},
1637 {"INFO", net_ads_printer_info},
1638 {"PUBLISH", net_ads_printer_publish},
1639 {"REMOVE", net_ads_printer_remove},
1640 {NULL, NULL}
1643 return net_run_function(argc, argv, func, net_ads_printer_usage);
1647 static int net_ads_password(int argc, const char **argv)
1649 ADS_STRUCT *ads;
1650 const char *auth_principal = opt_user_name;
1651 const char *auth_password = opt_password;
1652 char *realm = NULL;
1653 char *new_password = NULL;
1654 char *c, *prompt;
1655 const char *user;
1656 ADS_STATUS ret;
1658 if (opt_user_name == NULL || opt_password == NULL) {
1659 d_fprintf(stderr, "You must supply an administrator username/password\n");
1660 return -1;
1663 if (argc < 1) {
1664 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1665 return -1;
1668 user = argv[0];
1669 if (!strchr_m(user, '@')) {
1670 asprintf(&c, "%s@%s", argv[0], lp_realm());
1671 user = c;
1674 use_in_memory_ccache();
1675 c = strchr_m(auth_principal, '@');
1676 if (c) {
1677 realm = ++c;
1678 } else {
1679 realm = lp_realm();
1682 /* use the realm so we can eventually change passwords for users
1683 in realms other than default */
1684 if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
1685 return -1;
1688 /* we don't actually need a full connect, but it's the easy way to
1689 fill in the KDC's addresss */
1690 ads_connect(ads);
1692 if (!ads->config.realm) {
1693 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1694 return -1;
1697 if (argv[1]) {
1698 new_password = (char *)argv[1];
1699 } else {
1700 asprintf(&prompt, "Enter new password for %s:", user);
1701 new_password = getpass(prompt);
1702 free(prompt);
1705 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1706 auth_password, user, new_password, ads->auth.time_offset);
1707 if (!ADS_ERR_OK(ret)) {
1708 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1709 ads_destroy(&ads);
1710 return -1;
1713 d_printf("Password change for %s completed.\n", user);
1714 ads_destroy(&ads);
1716 return 0;
1719 int net_ads_changetrustpw(int argc, const char **argv)
1721 ADS_STRUCT *ads;
1722 char *host_principal;
1723 fstring my_name;
1724 ADS_STATUS ret;
1726 if (!secrets_init()) {
1727 DEBUG(1,("Failed to initialise secrets database\n"));
1728 return -1;
1731 net_use_krb_machine_account();
1733 use_in_memory_ccache();
1735 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1736 return -1;
1739 fstrcpy(my_name, global_myname());
1740 strlower_m(my_name);
1741 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1742 d_printf("Changing password for principal: %s\n", host_principal);
1744 ret = ads_change_trust_account_password(ads, host_principal);
1746 if (!ADS_ERR_OK(ret)) {
1747 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1748 ads_destroy(&ads);
1749 SAFE_FREE(host_principal);
1750 return -1;
1753 d_printf("Password change for principal %s succeeded.\n", host_principal);
1755 if (lp_use_kerberos_keytab()) {
1756 d_printf("Attempting to update system keytab with new password.\n");
1757 if (ads_keytab_create_default(ads)) {
1758 d_printf("Failed to update system keytab.\n");
1762 ads_destroy(&ads);
1763 SAFE_FREE(host_principal);
1765 return 0;
1769 help for net ads search
1771 static int net_ads_search_usage(int argc, const char **argv)
1773 d_printf(
1774 "\nnet ads search <expression> <attributes...>\n"\
1775 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1776 "The expression is a standard LDAP search expression, and the\n"\
1777 "attributes are a list of LDAP fields to show in the results\n\n"\
1778 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1780 net_common_flags_usage(argc, argv);
1781 return -1;
1786 general ADS search function. Useful in diagnosing problems in ADS
1788 static int net_ads_search(int argc, const char **argv)
1790 ADS_STRUCT *ads;
1791 ADS_STATUS rc;
1792 const char *ldap_exp;
1793 const char **attrs;
1794 LDAPMessage *res = NULL;
1796 if (argc < 1) {
1797 return net_ads_search_usage(argc, argv);
1800 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1801 return -1;
1804 ldap_exp = argv[0];
1805 attrs = (argv + 1);
1807 rc = ads_do_search_all(ads, ads->config.bind_path,
1808 LDAP_SCOPE_SUBTREE,
1809 ldap_exp, attrs, &res);
1810 if (!ADS_ERR_OK(rc)) {
1811 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1812 ads_destroy(&ads);
1813 return -1;
1816 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1818 /* dump the results */
1819 ads_dump(ads, res);
1821 ads_msgfree(ads, res);
1822 ads_destroy(&ads);
1824 return 0;
1829 help for net ads search
1831 static int net_ads_dn_usage(int argc, const char **argv)
1833 d_printf(
1834 "\nnet ads dn <dn> <attributes...>\n"\
1835 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1836 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1837 "to show in the results\n\n"\
1838 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1839 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1841 net_common_flags_usage(argc, argv);
1842 return -1;
1847 general ADS search function. Useful in diagnosing problems in ADS
1849 static int net_ads_dn(int argc, const char **argv)
1851 ADS_STRUCT *ads;
1852 ADS_STATUS rc;
1853 const char *dn;
1854 const char **attrs;
1855 LDAPMessage *res = NULL;
1857 if (argc < 1) {
1858 return net_ads_dn_usage(argc, argv);
1861 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1862 return -1;
1865 dn = argv[0];
1866 attrs = (argv + 1);
1868 rc = ads_do_search_all(ads, dn,
1869 LDAP_SCOPE_BASE,
1870 "(objectclass=*)", attrs, &res);
1871 if (!ADS_ERR_OK(rc)) {
1872 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1873 ads_destroy(&ads);
1874 return -1;
1877 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1879 /* dump the results */
1880 ads_dump(ads, res);
1882 ads_msgfree(ads, res);
1883 ads_destroy(&ads);
1885 return 0;
1889 help for net ads sid search
1891 static int net_ads_sid_usage(int argc, const char **argv)
1893 d_printf(
1894 "\nnet ads sid <sid> <attributes...>\n"\
1895 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1896 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
1897 "to show in the results\n\n"\
1898 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
1900 net_common_flags_usage(argc, argv);
1901 return -1;
1906 general ADS search function. Useful in diagnosing problems in ADS
1908 static int net_ads_sid(int argc, const char **argv)
1910 ADS_STRUCT *ads;
1911 ADS_STATUS rc;
1912 const char *sid_string;
1913 const char **attrs;
1914 LDAPMessage *res = NULL;
1915 DOM_SID sid;
1917 if (argc < 1) {
1918 return net_ads_sid_usage(argc, argv);
1921 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1922 return -1;
1925 sid_string = argv[0];
1926 attrs = (argv + 1);
1928 if (!string_to_sid(&sid, sid_string)) {
1929 d_fprintf(stderr, "could not convert sid\n");
1930 ads_destroy(&ads);
1931 return -1;
1934 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
1935 if (!ADS_ERR_OK(rc)) {
1936 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1937 ads_destroy(&ads);
1938 return -1;
1941 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1943 /* dump the results */
1944 ads_dump(ads, res);
1946 ads_msgfree(ads, res);
1947 ads_destroy(&ads);
1949 return 0;
1953 static int net_ads_keytab_usage(int argc, const char **argv)
1955 d_printf(
1956 "net ads keytab <COMMAND>\n"\
1957 "<COMMAND> can be either:\n"\
1958 " ADD Adds new service principal\n"\
1959 " CREATE Creates a fresh keytab\n"\
1960 " FLUSH Flushes out all keytab entries\n"\
1961 " HELP Prints this help message\n"\
1962 " LIST List the keytab\n"\
1963 "The ADD and LIST command will take arguments, the other commands\n"\
1964 "will not take any arguments. The arguments given to ADD\n"\
1965 "should be a list of principals to add. For example, \n"\
1966 " net ads keytab add srv1 srv2\n"\
1967 "will add principals for the services srv1 and srv2 to the\n"\
1968 "system's keytab.\n"\
1969 "The LIST command takes a keytabname.\n"\
1970 "\n"
1972 return -1;
1975 static int net_ads_keytab_flush(int argc, const char **argv)
1977 int ret;
1978 ADS_STRUCT *ads;
1980 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1981 return -1;
1983 ret = ads_keytab_flush(ads);
1984 ads_destroy(&ads);
1985 return ret;
1988 static int net_ads_keytab_add(int argc, const char **argv)
1990 int i;
1991 int ret = 0;
1992 ADS_STRUCT *ads;
1994 d_printf("Processing principals to add...\n");
1995 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1996 return -1;
1998 for (i = 0; i < argc; i++) {
1999 ret |= ads_keytab_add_entry(ads, argv[i]);
2001 ads_destroy(&ads);
2002 return ret;
2005 static int net_ads_keytab_create(int argc, const char **argv)
2007 ADS_STRUCT *ads;
2008 int ret;
2010 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2011 return -1;
2013 ret = ads_keytab_create_default(ads);
2014 ads_destroy(&ads);
2015 return ret;
2018 static int net_ads_keytab_list(int argc, const char **argv)
2020 const char *keytab = NULL;
2022 if (argc >= 1) {
2023 keytab = argv[0];
2026 return ads_keytab_list(keytab);
2030 int net_ads_keytab(int argc, const char **argv)
2032 struct functable func[] = {
2033 {"ADD", net_ads_keytab_add},
2034 {"CREATE", net_ads_keytab_create},
2035 {"FLUSH", net_ads_keytab_flush},
2036 {"HELP", net_ads_keytab_usage},
2037 {"LIST", net_ads_keytab_list},
2038 {NULL, NULL}
2041 if (!lp_use_kerberos_keytab()) {
2042 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2043 use keytab functions.\n");
2046 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2049 static int net_ads_kerberos_usage(int argc, const char **argv)
2051 d_printf(
2052 "net ads kerberos <COMMAND>\n"\
2053 "<COMMAND> can be either:\n"\
2054 " RENEW Renew TGT from existing credential cache\n"\
2055 " PAC Dumps the Kerberos PAC\n"\
2056 " KINIT Retrieve Ticket Granting Ticket (TGT)\n"\
2057 "\n"
2060 return -1;
2063 static int net_ads_kerberos_renew(int argc, const char **argv)
2065 int ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2066 if (ret) {
2067 d_printf("failed to renew kerberos ticket: %s\n",
2068 error_message(ret));
2070 return ret;
2073 static int net_ads_kerberos_pac(int argc, const char **argv)
2075 struct PAC_DATA *pac = NULL;
2076 struct PAC_LOGON_INFO *info = NULL;
2077 TALLOC_CTX *mem_ctx = NULL;
2078 NTSTATUS status;
2079 int ret = -1;
2081 mem_ctx = talloc_init("net_ads_kerberos_pac");
2082 if (!mem_ctx) {
2083 goto out;
2086 opt_password = net_prompt_pass(opt_user_name);
2088 status = kerberos_return_pac(mem_ctx,
2089 opt_user_name,
2090 opt_password,
2092 NULL,
2093 NULL,
2094 NULL,
2095 True,
2096 True,
2097 2592000, /* one month */
2098 &pac);
2099 if (!NT_STATUS_IS_OK(status)) {
2100 d_printf("failed to query kerberos PAC: %s\n",
2101 nt_errstr(status));
2102 goto out;
2105 info = get_logon_info_from_pac(pac);
2106 if (info) {
2107 const char *s;
2108 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2109 d_printf("The Pac: %s\n", s);
2112 ret = 0;
2113 out:
2114 TALLOC_FREE(mem_ctx);
2115 return ret;
2118 static int net_ads_kerberos_kinit(int argc, const char **argv)
2120 TALLOC_CTX *mem_ctx = NULL;
2121 int ret = -1;
2122 NTSTATUS status;
2124 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2125 if (!mem_ctx) {
2126 goto out;
2129 opt_password = net_prompt_pass(opt_user_name);
2131 ret = kerberos_kinit_password_ext(opt_user_name,
2132 opt_password,
2134 NULL,
2135 NULL,
2136 NULL,
2137 True,
2138 True,
2139 2592000, /* one month */
2140 &status);
2141 if (ret) {
2142 d_printf("failed to kinit password: %s\n",
2143 nt_errstr(status));
2145 out:
2146 return ret;
2149 int net_ads_kerberos(int argc, const char **argv)
2151 struct functable func[] = {
2152 {"KINIT", net_ads_kerberos_kinit},
2153 {"RENEW", net_ads_kerberos_renew},
2154 {"PAC", net_ads_kerberos_pac},
2155 {"HELP", net_ads_kerberos_usage},
2156 {NULL, NULL}
2159 return net_run_function(argc, argv, func, net_ads_kerberos_usage);
2163 int net_ads_help(int argc, const char **argv)
2165 struct functable func[] = {
2166 {"USER", net_ads_user_usage},
2167 {"GROUP", net_ads_group_usage},
2168 {"PRINTER", net_ads_printer_usage},
2169 {"SEARCH", net_ads_search_usage},
2170 {"INFO", net_ads_info},
2171 {"JOIN", net_ads_join_usage},
2172 {"DNS", net_ads_dns_usage},
2173 {"LEAVE", net_ads_leave},
2174 {"STATUS", net_ads_status},
2175 {"PASSWORD", net_ads_password},
2176 {"CHANGETRUSTPW", net_ads_changetrustpw},
2177 {NULL, NULL}
2180 return net_run_function(argc, argv, func, net_ads_usage);
2183 int net_ads(int argc, const char **argv)
2185 struct functable func[] = {
2186 {"INFO", net_ads_info},
2187 {"JOIN", net_ads_join},
2188 {"TESTJOIN", net_ads_testjoin},
2189 {"LEAVE", net_ads_leave},
2190 {"STATUS", net_ads_status},
2191 {"USER", net_ads_user},
2192 {"GROUP", net_ads_group},
2193 {"DNS", net_ads_dns},
2194 {"PASSWORD", net_ads_password},
2195 {"CHANGETRUSTPW", net_ads_changetrustpw},
2196 {"PRINTER", net_ads_printer},
2197 {"SEARCH", net_ads_search},
2198 {"DN", net_ads_dn},
2199 {"SID", net_ads_sid},
2200 {"WORKGROUP", net_ads_workgroup},
2201 {"LOOKUP", net_ads_lookup},
2202 {"KEYTAB", net_ads_keytab},
2203 {"GPO", net_ads_gpo},
2204 {"KERBEROS", net_ads_kerberos},
2205 {"HELP", net_ads_help},
2206 {NULL, NULL}
2209 return net_run_function(argc, argv, func, net_ads_usage);
2212 #else
2214 static int net_ads_noads(void)
2216 d_fprintf(stderr, "ADS support not compiled in\n");
2217 return -1;
2220 int net_ads_keytab(int argc, const char **argv)
2222 return net_ads_noads();
2225 int net_ads_kerberos(int argc, const char **argv)
2227 return net_ads_noads();
2230 int net_ads_usage(int argc, const char **argv)
2232 return net_ads_noads();
2235 int net_ads_help(int argc, const char **argv)
2237 return net_ads_noads();
2240 int net_ads_changetrustpw(int argc, const char **argv)
2242 return net_ads_noads();
2245 int net_ads_join(int argc, const char **argv)
2247 return net_ads_noads();
2250 int net_ads_user(int argc, const char **argv)
2252 return net_ads_noads();
2255 int net_ads_group(int argc, const char **argv)
2257 return net_ads_noads();
2260 /* this one shouldn't display a message */
2261 int net_ads_check(void)
2263 return -1;
2266 int net_ads_check_our_domain(void)
2268 return -1;
2271 int net_ads(int argc, const char **argv)
2273 return net_ads_usage(argc, argv);
2276 #endif /* WITH_ADS */