net: Make "net ads" use functable3
[Samba.git] / source / utils / net_ads.c
bloba71ba5b1d2e20845b9884045e492f9b1b57d4ead
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 /* when we do not have sufficient input parameters to contact a remote domain
31 * we always fall back to our own realm - Guenther*/
33 static const char *assume_own_realm(struct net_context *c)
35 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
36 return lp_realm();
39 return NULL;
43 do a cldap netlogon query
45 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
47 char addr[INET6_ADDRSTRLEN];
48 struct nbt_cldap_netlogon_5 reply;
50 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
51 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
52 d_fprintf(stderr, "CLDAP query failed!\n");
53 return -1;
56 d_printf("Information for Domain Controller: %s\n\n",
57 addr);
59 d_printf("Response Type: ");
60 switch (reply.type) {
61 case SAMLOGON_AD_UNK_R:
62 d_printf("SAMLOGON\n");
63 break;
64 case SAMLOGON_AD_R:
65 d_printf("SAMLOGON_USER\n");
66 break;
67 default:
68 d_printf("0x%x\n", reply.type);
69 break;
72 d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), reply.domain_uuid));
74 d_printf("Flags:\n"
75 "\tIs a PDC: %s\n"
76 "\tIs a GC of the forest: %s\n"
77 "\tIs an LDAP server: %s\n"
78 "\tSupports DS: %s\n"
79 "\tIs running a KDC: %s\n"
80 "\tIs running time services: %s\n"
81 "\tIs the closest DC: %s\n"
82 "\tIs writable: %s\n"
83 "\tHas a hardware clock: %s\n"
84 "\tIs a non-domain NC serviced by LDAP server: %s\n"
85 "\tIs NT6 DC that has some secrets: %s\n"
86 "\tIs NT6 DC that has all secrets: %s\n",
87 (reply.server_type & NBT_SERVER_PDC) ? "yes" : "no",
88 (reply.server_type & NBT_SERVER_GC) ? "yes" : "no",
89 (reply.server_type & NBT_SERVER_LDAP) ? "yes" : "no",
90 (reply.server_type & NBT_SERVER_DS) ? "yes" : "no",
91 (reply.server_type & NBT_SERVER_KDC) ? "yes" : "no",
92 (reply.server_type & NBT_SERVER_TIMESERV) ? "yes" : "no",
93 (reply.server_type & NBT_SERVER_CLOSEST) ? "yes" : "no",
94 (reply.server_type & NBT_SERVER_WRITABLE) ? "yes" : "no",
95 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? "yes" : "no",
96 (reply.server_type & NBT_SERVER_NDNC) ? "yes" : "no",
97 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? "yes" : "no",
98 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? "yes" : "no");
101 printf("Forest:\t\t\t%s\n", reply.forest);
102 printf("Domain:\t\t\t%s\n", reply.dns_domain);
103 printf("Domain Controller:\t%s\n", reply.pdc_dns_name);
105 printf("Pre-Win2k Domain:\t%s\n", reply.domain);
106 printf("Pre-Win2k Hostname:\t%s\n", reply.pdc_name);
108 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
110 printf("Server Site Name :\t\t%s\n", reply.server_site);
111 printf("Client Site Name :\t\t%s\n", reply.client_site);
113 d_printf("NT Version: %d\n", reply.nt_version);
114 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
115 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
117 return 0;
121 this implements the CLDAP based netlogon lookup requests
122 for finding the domain controller of a ADS domain
124 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
126 ADS_STRUCT *ads;
128 if (c->display_usage) {
129 d_printf("Usage:\n"
130 "net ads lookup\n"
131 " Find the ADS DC using CLDAP lookup.\n");
132 return 0;
135 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
136 d_fprintf(stderr, "Didn't find the cldap server!\n");
137 return -1;
140 if (!ads->config.realm) {
141 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
142 ads->ldap.port = 389;
145 return net_ads_cldap_netlogon(c, ads);
150 static int net_ads_info(struct net_context *c, int argc, const char **argv)
152 ADS_STRUCT *ads;
153 char addr[INET6_ADDRSTRLEN];
155 if (c->display_usage) {
156 d_printf("Usage:\n"
157 "net ads info\n"
158 " Display information about an Active Directory "
159 "server.\n");
160 return 0;
163 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
164 d_fprintf(stderr, "Didn't find the ldap server!\n");
165 return -1;
168 if (!ads || !ads->config.realm) {
169 d_fprintf(stderr, "Didn't find the ldap server!\n");
170 return -1;
173 /* Try to set the server's current time since we didn't do a full
174 TCP LDAP session initially */
176 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
177 d_fprintf( stderr, "Failed to get server's current time!\n");
180 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
182 d_printf("LDAP server: %s\n", addr);
183 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
184 d_printf("Realm: %s\n", ads->config.realm);
185 d_printf("Bind Path: %s\n", ads->config.bind_path);
186 d_printf("LDAP port: %d\n", ads->ldap.port);
187 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
189 d_printf("KDC server: %s\n", ads->auth.kdc_server );
190 d_printf("Server time offset: %d\n", ads->auth.time_offset );
192 return 0;
195 static void use_in_memory_ccache(void) {
196 /* Use in-memory credentials cache so we do not interfere with
197 * existing credentials */
198 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
201 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
202 uint32 auth_flags, ADS_STRUCT **ads_ret)
204 ADS_STRUCT *ads = NULL;
205 ADS_STATUS status;
206 bool need_password = false;
207 bool second_time = false;
208 char *cp;
209 const char *realm = NULL;
210 bool tried_closest_dc = false;
212 /* lp_realm() should be handled by a command line param,
213 However, the join requires that realm be set in smb.conf
214 and compares our realm with the remote server's so this is
215 ok until someone needs more flexibility */
217 *ads_ret = NULL;
219 retry_connect:
220 if (only_own_domain) {
221 realm = lp_realm();
222 } else {
223 realm = assume_own_realm(c);
226 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
228 if (!c->opt_user_name) {
229 c->opt_user_name = "administrator";
232 if (c->opt_user_specified) {
233 need_password = true;
236 retry:
237 if (!c->opt_password && need_password && !c->opt_machine_pass) {
238 c->opt_password = net_prompt_pass(c, c->opt_user_name);
239 if (!c->opt_password) {
240 ads_destroy(&ads);
241 return ADS_ERROR(LDAP_NO_MEMORY);
245 if (c->opt_password) {
246 use_in_memory_ccache();
247 SAFE_FREE(ads->auth.password);
248 ads->auth.password = smb_xstrdup(c->opt_password);
251 ads->auth.flags |= auth_flags;
252 SAFE_FREE(ads->auth.user_name);
253 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
256 * If the username is of the form "name@realm",
257 * extract the realm and convert to upper case.
258 * This is only used to establish the connection.
260 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
261 *cp++ = '\0';
262 SAFE_FREE(ads->auth.realm);
263 ads->auth.realm = smb_xstrdup(cp);
264 strupper_m(ads->auth.realm);
267 status = ads_connect(ads);
269 if (!ADS_ERR_OK(status)) {
271 if (NT_STATUS_EQUAL(ads_ntstatus(status),
272 NT_STATUS_NO_LOGON_SERVERS)) {
273 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
274 ads_destroy(&ads);
275 return status;
278 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
279 need_password = true;
280 second_time = true;
281 goto retry;
282 } else {
283 ads_destroy(&ads);
284 return status;
288 /* when contacting our own domain, make sure we use the closest DC.
289 * This is done by reconnecting to ADS because only the first call to
290 * ads_connect will give us our own sitename */
292 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
294 tried_closest_dc = true; /* avoid loop */
296 if (!ads->config.tried_closest_dc) {
298 namecache_delete(ads->server.realm, 0x1C);
299 namecache_delete(ads->server.workgroup, 0x1C);
301 ads_destroy(&ads);
302 ads = NULL;
304 goto retry_connect;
308 *ads_ret = ads;
309 return status;
312 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
314 return ads_startup_int(c, only_own_domain, 0, ads);
317 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
319 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
323 Check to see if connection can be made via ads.
324 ads_startup() stores the password in opt_password if it needs to so
325 that rpc or rap can use it without re-prompting.
327 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
329 ADS_STRUCT *ads;
330 ADS_STATUS status;
332 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
333 return -1;
336 ads->auth.flags |= ADS_AUTH_NO_BIND;
338 status = ads_connect(ads);
339 if ( !ADS_ERR_OK(status) ) {
340 return -1;
343 ads_destroy(&ads);
344 return 0;
347 int net_ads_check_our_domain(struct net_context *c)
349 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
352 int net_ads_check(struct net_context *c)
354 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
358 determine the netbios workgroup name for a domain
360 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
362 ADS_STRUCT *ads;
363 char addr[INET6_ADDRSTRLEN];
364 struct nbt_cldap_netlogon_5 reply;
366 if (c->display_usage) {
367 d_printf("Usage:\n"
368 "net ads workgroup\n"
369 " Print the workgroup name\n");
370 return 0;
373 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
374 d_fprintf(stderr, "Didn't find the cldap server!\n");
375 return -1;
378 if (!ads->config.realm) {
379 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
380 ads->ldap.port = 389;
383 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
384 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
385 d_fprintf(stderr, "CLDAP query failed!\n");
386 return -1;
389 d_printf("Workgroup: %s\n", reply.domain);
391 ads_destroy(&ads);
393 return 0;
398 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
400 char **disp_fields = (char **) data_area;
402 if (!field) { /* must be end of record */
403 if (disp_fields[0]) {
404 if (!strchr_m(disp_fields[0], '$')) {
405 if (disp_fields[1])
406 d_printf("%-21.21s %s\n",
407 disp_fields[0], disp_fields[1]);
408 else
409 d_printf("%s\n", disp_fields[0]);
412 SAFE_FREE(disp_fields[0]);
413 SAFE_FREE(disp_fields[1]);
414 return true;
416 if (!values) /* must be new field, indicate string field */
417 return true;
418 if (StrCaseCmp(field, "sAMAccountName") == 0) {
419 disp_fields[0] = SMB_STRDUP((char *) values[0]);
421 if (StrCaseCmp(field, "description") == 0)
422 disp_fields[1] = SMB_STRDUP((char *) values[0]);
423 return true;
426 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
428 return net_user_usage(c, argc, argv);
431 static int ads_user_add(struct net_context *c, int argc, const char **argv)
433 ADS_STRUCT *ads;
434 ADS_STATUS status;
435 char *upn, *userdn;
436 LDAPMessage *res=NULL;
437 int rc = -1;
438 char *ou_str = NULL;
440 if (argc < 1 || c->display_usage)
441 return net_ads_user_usage(c, argc, argv);
443 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
444 return -1;
447 status = ads_find_user_acct(ads, &res, argv[0]);
449 if (!ADS_ERR_OK(status)) {
450 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
451 goto done;
454 if (ads_count_replies(ads, res)) {
455 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
456 goto done;
459 if (c->opt_container) {
460 ou_str = SMB_STRDUP(c->opt_container);
461 } else {
462 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
465 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
467 if (!ADS_ERR_OK(status)) {
468 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
469 ads_errstr(status));
470 goto done;
473 /* if no password is to be set, we're done */
474 if (argc == 1) {
475 d_printf("User %s added\n", argv[0]);
476 rc = 0;
477 goto done;
480 /* try setting the password */
481 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
482 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
483 ads->auth.time_offset);
484 safe_free(upn);
485 if (ADS_ERR_OK(status)) {
486 d_printf("User %s added\n", argv[0]);
487 rc = 0;
488 goto done;
491 /* password didn't set, delete account */
492 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
493 argv[0], ads_errstr(status));
494 ads_msgfree(ads, res);
495 status=ads_find_user_acct(ads, &res, argv[0]);
496 if (ADS_ERR_OK(status)) {
497 userdn = ads_get_dn(ads, res);
498 ads_del_dn(ads, userdn);
499 ads_memfree(ads, userdn);
502 done:
503 if (res)
504 ads_msgfree(ads, res);
505 ads_destroy(&ads);
506 SAFE_FREE(ou_str);
507 return rc;
510 static int ads_user_info(struct net_context *c, int argc, const char **argv)
512 ADS_STRUCT *ads;
513 ADS_STATUS rc;
514 LDAPMessage *res;
515 const char *attrs[] = {"memberOf", NULL};
516 char *searchstring=NULL;
517 char **grouplist;
518 char *escaped_user;
520 if (argc < 1 || c->display_usage) {
521 return net_ads_user_usage(c, argc, argv);
524 escaped_user = escape_ldap_string_alloc(argv[0]);
526 if (!escaped_user) {
527 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
528 return -1;
531 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
532 SAFE_FREE(escaped_user);
533 return -1;
536 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
537 rc = ads_search(ads, &res, searchstring, attrs);
538 safe_free(searchstring);
540 if (!ADS_ERR_OK(rc)) {
541 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
542 ads_destroy(&ads);
543 SAFE_FREE(escaped_user);
544 return -1;
547 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
548 (LDAPMessage *)res, "memberOf");
550 if (grouplist) {
551 int i;
552 char **groupname;
553 for (i=0;grouplist[i];i++) {
554 groupname = ldap_explode_dn(grouplist[i], 1);
555 d_printf("%s\n", groupname[0]);
556 ldap_value_free(groupname);
558 ldap_value_free(grouplist);
561 ads_msgfree(ads, res);
562 ads_destroy(&ads);
563 SAFE_FREE(escaped_user);
564 return 0;
567 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
569 ADS_STRUCT *ads;
570 ADS_STATUS rc;
571 LDAPMessage *res = NULL;
572 char *userdn;
574 if (argc < 1) {
575 return net_ads_user_usage(c, argc, argv);
578 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
579 return -1;
582 rc = ads_find_user_acct(ads, &res, argv[0]);
583 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
584 d_printf("User %s does not exist.\n", argv[0]);
585 ads_msgfree(ads, res);
586 ads_destroy(&ads);
587 return -1;
589 userdn = ads_get_dn(ads, res);
590 ads_msgfree(ads, res);
591 rc = ads_del_dn(ads, userdn);
592 ads_memfree(ads, userdn);
593 if (ADS_ERR_OK(rc)) {
594 d_printf("User %s deleted\n", argv[0]);
595 ads_destroy(&ads);
596 return 0;
598 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
599 ads_errstr(rc));
600 ads_destroy(&ads);
601 return -1;
604 int net_ads_user(struct net_context *c, int argc, const char **argv)
606 struct functable3 func[] = {
608 "add",
609 ads_user_add,
610 NET_TRANSPORT_ADS,
611 "Add an AD user",
612 "net ads user add\n"
613 " Add an AD user"
616 "info",
617 ads_user_info,
618 NET_TRANSPORT_ADS,
619 "Display information about an AD user",
620 "net ads user info\n"
621 " Display information about an AD user"
624 "delete",
625 ads_user_delete,
626 NET_TRANSPORT_ADS,
627 "Delete an AD user",
628 "net ads user delete\n"
629 " Delete an AD user"
631 {NULL, NULL, 0, NULL, NULL}
633 ADS_STRUCT *ads;
634 ADS_STATUS rc;
635 const char *shortattrs[] = {"sAMAccountName", NULL};
636 const char *longattrs[] = {"sAMAccountName", "description", NULL};
637 char *disp_fields[2] = {NULL, NULL};
639 if (argc == 0) {
640 if (c->display_usage) {
641 d_printf("Usage:\n");
642 d_printf("net ads user\n"
643 " List AD users\n");
644 net_display_usage_from_functable(func);
645 return 0;
648 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
649 return -1;
652 if (c->opt_long_list_entries)
653 d_printf("\nUser name Comment"
654 "\n-----------------------------\n");
656 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
657 LDAP_SCOPE_SUBTREE,
658 "(objectCategory=user)",
659 c->opt_long_list_entries ? longattrs :
660 shortattrs, usergrp_display,
661 disp_fields);
662 ads_destroy(&ads);
663 return ADS_ERR_OK(rc) ? 0 : -1;
666 return net_run_function3(c, argc, argv, "net ads user", func);
669 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
671 return net_group_usage(c, argc, argv);
674 static int ads_group_add(struct net_context *c, int argc, const char **argv)
676 ADS_STRUCT *ads;
677 ADS_STATUS status;
678 LDAPMessage *res=NULL;
679 int rc = -1;
680 char *ou_str = NULL;
682 if (argc < 1 || c->display_usage) {
683 return net_ads_group_usage(c, argc, argv);
686 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
687 return -1;
690 status = ads_find_user_acct(ads, &res, argv[0]);
692 if (!ADS_ERR_OK(status)) {
693 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
694 goto done;
697 if (ads_count_replies(ads, res)) {
698 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
699 goto done;
702 if (c->opt_container) {
703 ou_str = SMB_STRDUP(c->opt_container);
704 } else {
705 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
708 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
710 if (ADS_ERR_OK(status)) {
711 d_printf("Group %s added\n", argv[0]);
712 rc = 0;
713 } else {
714 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
715 ads_errstr(status));
718 done:
719 if (res)
720 ads_msgfree(ads, res);
721 ads_destroy(&ads);
722 SAFE_FREE(ou_str);
723 return rc;
726 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
728 ADS_STRUCT *ads;
729 ADS_STATUS rc;
730 LDAPMessage *res = NULL;
731 char *groupdn;
733 if (argc < 1 || c->display_usage) {
734 return net_ads_group_usage(c, argc, argv);
737 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
738 return -1;
741 rc = ads_find_user_acct(ads, &res, argv[0]);
742 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
743 d_printf("Group %s does not exist.\n", argv[0]);
744 ads_msgfree(ads, res);
745 ads_destroy(&ads);
746 return -1;
748 groupdn = ads_get_dn(ads, res);
749 ads_msgfree(ads, res);
750 rc = ads_del_dn(ads, groupdn);
751 ads_memfree(ads, groupdn);
752 if (ADS_ERR_OK(rc)) {
753 d_printf("Group %s deleted\n", argv[0]);
754 ads_destroy(&ads);
755 return 0;
757 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
758 ads_errstr(rc));
759 ads_destroy(&ads);
760 return -1;
763 int net_ads_group(struct net_context *c, int argc, const char **argv)
765 struct functable3 func[] = {
767 "add",
768 ads_group_add,
769 NET_TRANSPORT_ADS,
770 "Add an AD group",
771 "net ads group add\n"
772 " Add an AD group"
775 "delete",
776 ads_group_delete,
777 NET_TRANSPORT_ADS,
778 "Delete an AD group",
779 "net ads group delete\n"
780 " Delete an AD group"
782 {NULL, NULL, 0, NULL, NULL}
784 ADS_STRUCT *ads;
785 ADS_STATUS rc;
786 const char *shortattrs[] = {"sAMAccountName", NULL};
787 const char *longattrs[] = {"sAMAccountName", "description", NULL};
788 char *disp_fields[2] = {NULL, NULL};
790 if (argc == 0) {
791 if (c->display_usage) {
792 d_printf("Usage:\n");
793 d_printf("net ads group\n"
794 " List AD groups\n");
795 net_display_usage_from_functable(func);
796 return 0;
799 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
800 return -1;
803 if (c->opt_long_list_entries)
804 d_printf("\nGroup name Comment"
805 "\n-----------------------------\n");
806 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
807 LDAP_SCOPE_SUBTREE,
808 "(objectCategory=group)",
809 c->opt_long_list_entries ? longattrs :
810 shortattrs, usergrp_display,
811 disp_fields);
813 ads_destroy(&ads);
814 return ADS_ERR_OK(rc) ? 0 : -1;
816 return net_run_function3(c, argc, argv, "net ads group", func);
819 static int net_ads_status(struct net_context *c, int argc, const char **argv)
821 ADS_STRUCT *ads;
822 ADS_STATUS rc;
823 LDAPMessage *res;
825 if (c->display_usage) {
826 d_printf("Usage:\n"
827 "net ads status\n"
828 " Display machine account details\n");
829 return 0;
832 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
833 return -1;
836 rc = ads_find_machine_acct(ads, &res, global_myname());
837 if (!ADS_ERR_OK(rc)) {
838 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
839 ads_destroy(&ads);
840 return -1;
843 if (ads_count_replies(ads, res) == 0) {
844 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
845 ads_destroy(&ads);
846 return -1;
849 ads_dump(ads, res);
850 ads_destroy(&ads);
851 return 0;
854 /*******************************************************************
855 Leave an AD domain. Windows XP disables the machine account.
856 We'll try the same. The old code would do an LDAP delete.
857 That only worked using the machine creds because added the machine
858 with full control to the computer object's ACL.
859 *******************************************************************/
861 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
863 TALLOC_CTX *ctx;
864 struct libnet_UnjoinCtx *r = NULL;
865 WERROR werr;
867 if (c->display_usage) {
868 d_printf("Usage:\n"
869 "net ads leave\n"
870 " Leave an AD domain\n");
871 return 0;
874 if (!*lp_realm()) {
875 d_fprintf(stderr, "No realm set, are we joined ?\n");
876 return -1;
879 if (!(ctx = talloc_init("net_ads_leave"))) {
880 d_fprintf(stderr, "Could not initialise talloc context.\n");
881 return -1;
884 use_in_memory_ccache();
886 werr = libnet_init_UnjoinCtx(ctx, &r);
887 if (!W_ERROR_IS_OK(werr)) {
888 d_fprintf(stderr, "Could not initialise unjoin context.\n");
889 return -1;
892 r->in.debug = true;
893 r->in.dc_name = c->opt_host;
894 r->in.domain_name = lp_realm();
895 r->in.admin_account = c->opt_user_name;
896 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
897 r->in.modify_config = lp_config_backend_is_registry();
898 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
899 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
901 werr = libnet_Unjoin(ctx, r);
902 if (!W_ERROR_IS_OK(werr)) {
903 d_printf("Failed to leave domain: %s\n",
904 r->out.error_string ? r->out.error_string :
905 get_friendly_werror_msg(werr));
906 goto done;
909 if (W_ERROR_IS_OK(werr)) {
910 d_printf("Deleted account for '%s' in realm '%s'\n",
911 r->in.machine_name, r->out.dns_domain_name);
912 goto done;
915 /* We couldn't delete it - see if the disable succeeded. */
916 if (r->out.disabled_machine_account) {
917 d_printf("Disabled account for '%s' in realm '%s'\n",
918 r->in.machine_name, r->out.dns_domain_name);
919 werr = WERR_OK;
920 goto done;
923 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
924 r->in.machine_name, r->out.dns_domain_name);
926 done:
927 TALLOC_FREE(r);
928 TALLOC_FREE(ctx);
930 if (W_ERROR_IS_OK(werr)) {
931 return 0;
934 return -1;
937 static NTSTATUS net_ads_join_ok(struct net_context *c)
939 ADS_STRUCT *ads = NULL;
940 ADS_STATUS status;
942 if (!secrets_init()) {
943 DEBUG(1,("Failed to initialise secrets database\n"));
944 return NT_STATUS_ACCESS_DENIED;
947 net_use_krb_machine_account(c);
949 status = ads_startup(c, true, &ads);
950 if (!ADS_ERR_OK(status)) {
951 return ads_ntstatus(status);
954 ads_destroy(&ads);
955 return NT_STATUS_OK;
959 check that an existing join is OK
961 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
963 NTSTATUS status;
964 use_in_memory_ccache();
966 if (c->display_usage) {
967 d_printf("Usage:\n"
968 "net ads testjoin\n"
969 " Test if the existing join is ok\n");
970 return 0;
973 /* Display success or failure */
974 status = net_ads_join_ok(c);
975 if (!NT_STATUS_IS_OK(status)) {
976 fprintf(stderr,"Join to domain is not valid: %s\n",
977 get_friendly_nt_error_msg(status));
978 return -1;
981 printf("Join is OK\n");
982 return 0;
985 /*******************************************************************
986 Simple configu checks before beginning the join
987 ********************************************************************/
989 static WERROR check_ads_config( void )
991 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
992 d_printf("Host is not configured as a member server.\n");
993 return WERR_INVALID_DOMAIN_ROLE;
996 if (strlen(global_myname()) > 15) {
997 d_printf("Our netbios name can be at most 15 chars long, "
998 "\"%s\" is %u chars long\n", global_myname(),
999 (unsigned int)strlen(global_myname()));
1000 return WERR_INVALID_COMPUTER_NAME;
1003 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1004 d_fprintf(stderr, "realm must be set in in %s for ADS "
1005 "join to succeed.\n", get_dyn_CONFIGFILE());
1006 return WERR_INVALID_PARAM;
1009 return WERR_OK;
1012 /*******************************************************************
1013 Send a DNS update request
1014 *******************************************************************/
1016 #if defined(WITH_DNS_UPDATES)
1017 #include "dns.h"
1018 DNS_ERROR DoDNSUpdate(char *pszServerName,
1019 const char *pszDomainName, const char *pszHostName,
1020 const struct sockaddr_storage *sslist,
1021 size_t num_addrs );
1023 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1024 const char *machine_name,
1025 const struct sockaddr_storage *addrs,
1026 int num_addrs)
1028 struct dns_rr_ns *nameservers = NULL;
1029 int ns_count = 0;
1030 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1031 DNS_ERROR dns_err;
1032 fstring dns_server;
1033 const char *dnsdomain = NULL;
1034 char *root_domain = NULL;
1036 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1037 d_printf("No DNS domain configured for %s. "
1038 "Unable to perform DNS Update.\n", machine_name);
1039 status = NT_STATUS_INVALID_PARAMETER;
1040 goto done;
1042 dnsdomain++;
1044 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1045 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1046 /* Child domains often do not have NS records. Look
1047 for the NS record for the forest root domain
1048 (rootDomainNamingContext in therootDSE) */
1050 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1051 LDAPMessage *msg = NULL;
1052 char *root_dn;
1053 ADS_STATUS ads_status;
1055 if ( !ads->ldap.ld ) {
1056 ads_status = ads_connect( ads );
1057 if ( !ADS_ERR_OK(ads_status) ) {
1058 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1059 goto done;
1063 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1064 "(objectclass=*)", rootname_attrs, &msg);
1065 if (!ADS_ERR_OK(ads_status)) {
1066 goto done;
1069 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1070 if ( !root_dn ) {
1071 ads_msgfree( ads, msg );
1072 goto done;
1075 root_domain = ads_build_domain( root_dn );
1077 /* cleanup */
1078 ads_msgfree( ads, msg );
1080 /* try again for NS servers */
1082 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1084 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1085 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1086 "realm\n", ads->config.realm));
1087 goto done;
1090 dnsdomain = root_domain;
1094 /* Now perform the dns update - we'll try non-secure and if we fail,
1095 we'll follow it up with a secure update */
1097 fstrcpy( dns_server, nameservers[0].hostname );
1099 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1100 if (!ERR_DNS_IS_OK(dns_err)) {
1101 status = NT_STATUS_UNSUCCESSFUL;
1104 done:
1106 SAFE_FREE( root_domain );
1108 return status;
1111 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1113 int num_addrs;
1114 struct sockaddr_storage *iplist = NULL;
1115 fstring machine_name;
1116 NTSTATUS status;
1118 name_to_fqdn( machine_name, global_myname() );
1119 strlower_m( machine_name );
1121 /* Get our ip address (not the 127.0.0.x address but a real ip
1122 * address) */
1124 num_addrs = get_my_ip_address( &iplist );
1125 if ( num_addrs <= 0 ) {
1126 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1127 "addresses!\n"));
1128 return NT_STATUS_INVALID_PARAMETER;
1131 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1132 iplist, num_addrs);
1133 SAFE_FREE( iplist );
1134 return status;
1136 #endif
1139 /*******************************************************************
1140 ********************************************************************/
1142 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1144 d_printf("net ads join [options]\n");
1145 d_printf("Valid options:\n");
1146 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1147 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1148 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1149 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1150 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1151 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1152 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1153 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1154 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1155 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1156 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1157 d_printf(" the two other attributes.\n");
1159 return -1;
1162 /*******************************************************************
1163 ********************************************************************/
1165 int net_ads_join(struct net_context *c, int argc, const char **argv)
1167 TALLOC_CTX *ctx = NULL;
1168 struct libnet_JoinCtx *r = NULL;
1169 const char *domain = lp_realm();
1170 WERROR werr = WERR_SETUP_NOT_JOINED;
1171 bool createupn = false;
1172 const char *machineupn = NULL;
1173 const char *create_in_ou = NULL;
1174 int i;
1175 const char *os_name = NULL;
1176 const char *os_version = NULL;
1177 bool modify_config = lp_config_backend_is_registry();
1179 if (c->display_usage)
1180 return net_ads_join_usage(c, argc, argv);
1182 if (!modify_config) {
1184 werr = check_ads_config();
1185 if (!W_ERROR_IS_OK(werr)) {
1186 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1187 goto fail;
1191 if (!(ctx = talloc_init("net_ads_join"))) {
1192 d_fprintf(stderr, "Could not initialise talloc context.\n");
1193 werr = WERR_NOMEM;
1194 goto fail;
1197 use_in_memory_ccache();
1199 werr = libnet_init_JoinCtx(ctx, &r);
1200 if (!W_ERROR_IS_OK(werr)) {
1201 goto fail;
1204 /* process additional command line args */
1206 for ( i=0; i<argc; i++ ) {
1207 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1208 createupn = true;
1209 machineupn = get_string_param(argv[i]);
1211 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1212 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1213 d_fprintf(stderr, "Please supply a valid OU path.\n");
1214 werr = WERR_INVALID_PARAM;
1215 goto fail;
1218 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1219 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1220 d_fprintf(stderr, "Please supply a operating system name.\n");
1221 werr = WERR_INVALID_PARAM;
1222 goto fail;
1225 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1226 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1227 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1228 werr = WERR_INVALID_PARAM;
1229 goto fail;
1232 else {
1233 domain = argv[i];
1237 if (!*domain) {
1238 d_fprintf(stderr, "Please supply a valid domain name\n");
1239 werr = WERR_INVALID_PARAM;
1240 goto fail;
1243 /* Do the domain join here */
1245 r->in.domain_name = domain;
1246 r->in.create_upn = createupn;
1247 r->in.upn = machineupn;
1248 r->in.account_ou = create_in_ou;
1249 r->in.os_name = os_name;
1250 r->in.os_version = os_version;
1251 r->in.dc_name = c->opt_host;
1252 r->in.admin_account = c->opt_user_name;
1253 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1254 r->in.debug = true;
1255 r->in.modify_config = modify_config;
1256 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1257 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1258 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1260 werr = libnet_Join(ctx, r);
1261 if (!W_ERROR_IS_OK(werr)) {
1262 goto fail;
1265 /* Check the short name of the domain */
1267 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1268 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1269 d_printf("domain name obtained from the server.\n");
1270 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1271 d_printf("You should set \"workgroup = %s\" in %s.\n",
1272 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1275 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1277 if (r->out.dns_domain_name) {
1278 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1279 r->out.dns_domain_name);
1280 } else {
1281 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1282 r->out.netbios_domain_name);
1285 #if defined(WITH_DNS_UPDATES)
1286 if (r->out.domain_is_ad) {
1287 /* We enter this block with user creds */
1288 ADS_STRUCT *ads_dns = NULL;
1290 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1291 /* kinit with the machine password */
1293 use_in_memory_ccache();
1294 asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1295 ads_dns->auth.password = secrets_fetch_machine_password(
1296 r->out.netbios_domain_name, NULL, NULL );
1297 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1298 strupper_m(ads_dns->auth.realm );
1299 ads_kinit_password( ads_dns );
1302 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1303 d_fprintf( stderr, "DNS update failed!\n" );
1306 /* exit from this block using machine creds */
1307 ads_destroy(&ads_dns);
1309 #endif
1310 TALLOC_FREE(r);
1311 TALLOC_FREE( ctx );
1313 return 0;
1315 fail:
1316 /* issue an overall failure message at the end. */
1317 d_printf("Failed to join domain: %s\n",
1318 r && r->out.error_string ? r->out.error_string :
1319 get_friendly_werror_msg(werr));
1320 TALLOC_FREE( ctx );
1322 return -1;
1325 /*******************************************************************
1326 ********************************************************************/
1328 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1330 #if defined(WITH_DNS_UPDATES)
1331 ADS_STRUCT *ads;
1332 ADS_STATUS status;
1333 TALLOC_CTX *ctx;
1335 #ifdef DEVELOPER
1336 talloc_enable_leak_report();
1337 #endif
1339 if (argc > 0 || c->display_usage) {
1340 d_printf("Usage:\n"
1341 "net ads dns register\n"
1342 " Register hostname with DNS\n");
1343 return -1;
1346 if (!(ctx = talloc_init("net_ads_dns"))) {
1347 d_fprintf(stderr, "Could not initialise talloc context\n");
1348 return -1;
1351 status = ads_startup(c, true, &ads);
1352 if ( !ADS_ERR_OK(status) ) {
1353 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1354 TALLOC_FREE(ctx);
1355 return -1;
1358 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1359 d_fprintf( stderr, "DNS update failed!\n" );
1360 ads_destroy( &ads );
1361 TALLOC_FREE( ctx );
1362 return -1;
1365 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1367 ads_destroy(&ads);
1368 TALLOC_FREE( ctx );
1370 return 0;
1371 #else
1372 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1373 return -1;
1374 #endif
1377 #if defined(WITH_DNS_UPDATES)
1378 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1379 #endif
1381 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1383 #if defined(WITH_DNS_UPDATES)
1384 DNS_ERROR err;
1386 #ifdef DEVELOPER
1387 talloc_enable_leak_report();
1388 #endif
1390 if (argc != 2 || c->display_usage) {
1391 d_printf("Usage:\n"
1392 "net ads dns gethostbyname <server> <name>\n"
1393 " Look up hostname from the AD\n"
1394 " server\tName server to use\n"
1395 " name\tName to look up\n");
1396 return -1;
1399 err = do_gethostbyname(argv[0], argv[1]);
1401 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1402 #endif
1403 return 0;
1406 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1408 struct functable3 func[] = {
1410 "register",
1411 net_ads_dns_register,
1412 NET_TRANSPORT_ADS,
1413 "Add host dns entry to AD",
1414 "net ads dns register\n"
1415 " Add host dns entry to AD"
1418 "gethostbyname",
1419 net_ads_dns_gethostbyname,
1420 NET_TRANSPORT_ADS,
1421 "Look up host",
1422 "net ads dns gethostbyname\n"
1423 " Look up host"
1425 {NULL, NULL, 0, NULL, NULL}
1428 return net_run_function3(c, argc, argv, "net ads dns", func);
1431 /*******************************************************************
1432 ********************************************************************/
1434 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1436 d_printf(
1437 "\nnet ads printer search <printer>"
1438 "\n\tsearch for a printer in the directory\n"
1439 "\nnet ads printer info <printer> <server>"
1440 "\n\tlookup info in directory for printer on server"
1441 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1442 "\nnet ads printer publish <printername>"
1443 "\n\tpublish printer in directory"
1444 "\n\t(note: printer name is required)\n"
1445 "\nnet ads printer remove <printername>"
1446 "\n\tremove printer from directory"
1447 "\n\t(note: printer name is required)\n");
1448 return -1;
1451 /*******************************************************************
1452 ********************************************************************/
1454 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1456 ADS_STRUCT *ads;
1457 ADS_STATUS rc;
1458 LDAPMessage *res = NULL;
1460 if (c->display_usage) {
1461 d_printf("Usage:\n"
1462 "net ads printer search\n"
1463 " List printers in the AD\n");
1464 return 0;
1467 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1468 return -1;
1471 rc = ads_find_printers(ads, &res);
1473 if (!ADS_ERR_OK(rc)) {
1474 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1475 ads_msgfree(ads, res);
1476 ads_destroy(&ads);
1477 return -1;
1480 if (ads_count_replies(ads, res) == 0) {
1481 d_fprintf(stderr, "No results found\n");
1482 ads_msgfree(ads, res);
1483 ads_destroy(&ads);
1484 return -1;
1487 ads_dump(ads, res);
1488 ads_msgfree(ads, res);
1489 ads_destroy(&ads);
1490 return 0;
1493 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1495 ADS_STRUCT *ads;
1496 ADS_STATUS rc;
1497 const char *servername, *printername;
1498 LDAPMessage *res = NULL;
1500 if (c->display_usage) {
1501 d_printf("Usage:\n"
1502 "net ads printer info [printername [servername]]\n"
1503 " Display printer info from AD\n"
1504 " printername\tPrinter name or wildcard\n"
1505 " servername\tName of the print server\n");
1506 return 0;
1509 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1510 return -1;
1513 if (argc > 0) {
1514 printername = argv[0];
1515 } else {
1516 printername = "*";
1519 if (argc > 1) {
1520 servername = argv[1];
1521 } else {
1522 servername = global_myname();
1525 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1527 if (!ADS_ERR_OK(rc)) {
1528 d_fprintf(stderr, "Server '%s' not found: %s\n",
1529 servername, ads_errstr(rc));
1530 ads_msgfree(ads, res);
1531 ads_destroy(&ads);
1532 return -1;
1535 if (ads_count_replies(ads, res) == 0) {
1536 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1537 ads_msgfree(ads, res);
1538 ads_destroy(&ads);
1539 return -1;
1542 ads_dump(ads, res);
1543 ads_msgfree(ads, res);
1544 ads_destroy(&ads);
1546 return 0;
1549 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1551 ADS_STRUCT *ads;
1552 ADS_STATUS rc;
1553 const char *servername, *printername;
1554 struct cli_state *cli;
1555 struct rpc_pipe_client *pipe_hnd;
1556 struct sockaddr_storage server_ss;
1557 NTSTATUS nt_status;
1558 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1559 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1560 char *prt_dn, *srv_dn, **srv_cn;
1561 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1562 LDAPMessage *res = NULL;
1564 if (argc < 1 || c->display_usage) {
1565 d_printf("Usage:\n"
1566 "net ads printer publish <printername> [servername]\n"
1567 " Publish printer in AD\n"
1568 " printername\tName of the printer\n"
1569 " servername\tName of the print server\n");
1570 talloc_destroy(mem_ctx);
1571 return -1;
1574 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1575 talloc_destroy(mem_ctx);
1576 return -1;
1579 printername = argv[0];
1581 if (argc == 2) {
1582 servername = argv[1];
1583 } else {
1584 servername = global_myname();
1587 /* Get printer data from SPOOLSS */
1589 resolve_name(servername, &server_ss, 0x20);
1591 nt_status = cli_full_connection(&cli, global_myname(), servername,
1592 &server_ss, 0,
1593 "IPC$", "IPC",
1594 c->opt_user_name, c->opt_workgroup,
1595 c->opt_password ? c->opt_password : "",
1596 CLI_FULL_CONNECTION_USE_KERBEROS,
1597 Undefined, NULL);
1599 if (NT_STATUS_IS_ERR(nt_status)) {
1600 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1601 "for %s\n", servername, printername);
1602 ads_destroy(&ads);
1603 talloc_destroy(mem_ctx);
1604 return -1;
1607 /* Publish on AD server */
1609 ads_find_machine_acct(ads, &res, servername);
1611 if (ads_count_replies(ads, res) == 0) {
1612 d_fprintf(stderr, "Could not find machine account for server %s\n",
1613 servername);
1614 ads_destroy(&ads);
1615 talloc_destroy(mem_ctx);
1616 return -1;
1619 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1620 srv_cn = ldap_explode_dn(srv_dn, 1);
1622 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1623 printername_escaped = escape_rdn_val_string_alloc(printername);
1624 if (!srv_cn_escaped || !printername_escaped) {
1625 SAFE_FREE(srv_cn_escaped);
1626 SAFE_FREE(printername_escaped);
1627 d_fprintf(stderr, "Internal error, out of memory!");
1628 ads_destroy(&ads);
1629 talloc_destroy(mem_ctx);
1630 return -1;
1633 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1635 SAFE_FREE(srv_cn_escaped);
1636 SAFE_FREE(printername_escaped);
1638 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1639 if (!pipe_hnd) {
1640 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1641 servername);
1642 SAFE_FREE(prt_dn);
1643 ads_destroy(&ads);
1644 talloc_destroy(mem_ctx);
1645 return -1;
1648 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1649 printername))) {
1650 SAFE_FREE(prt_dn);
1651 ads_destroy(&ads);
1652 talloc_destroy(mem_ctx);
1653 return -1;
1656 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1657 if (!ADS_ERR_OK(rc)) {
1658 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1659 SAFE_FREE(prt_dn);
1660 ads_destroy(&ads);
1661 talloc_destroy(mem_ctx);
1662 return -1;
1665 d_printf("published printer\n");
1666 SAFE_FREE(prt_dn);
1667 ads_destroy(&ads);
1668 talloc_destroy(mem_ctx);
1670 return 0;
1673 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1675 ADS_STRUCT *ads;
1676 ADS_STATUS rc;
1677 const char *servername;
1678 char *prt_dn;
1679 LDAPMessage *res = NULL;
1681 if (argc < 1 || c->display_usage) {
1682 d_printf("Usage:\n"
1683 "net ads printer remove <printername> [servername]\n"
1684 " Remove a printer from the AD\n"
1685 " printername\tName of the printer\n"
1686 " servername\tName of the print server\n");
1687 return -1;
1690 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1691 return -1;
1694 if (argc > 1) {
1695 servername = argv[1];
1696 } else {
1697 servername = global_myname();
1700 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1702 if (!ADS_ERR_OK(rc)) {
1703 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1704 ads_msgfree(ads, res);
1705 ads_destroy(&ads);
1706 return -1;
1709 if (ads_count_replies(ads, res) == 0) {
1710 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1711 ads_msgfree(ads, res);
1712 ads_destroy(&ads);
1713 return -1;
1716 prt_dn = ads_get_dn(ads, res);
1717 ads_msgfree(ads, res);
1718 rc = ads_del_dn(ads, prt_dn);
1719 ads_memfree(ads, prt_dn);
1721 if (!ADS_ERR_OK(rc)) {
1722 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1723 ads_destroy(&ads);
1724 return -1;
1727 ads_destroy(&ads);
1728 return 0;
1731 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1733 struct functable3 func[] = {
1735 "search",
1736 net_ads_printer_search,
1737 NET_TRANSPORT_ADS,
1738 "Search for a printer",
1739 "net ads printer search\n"
1740 " Search for a printer"
1743 "info",
1744 net_ads_printer_info,
1745 NET_TRANSPORT_ADS,
1746 "Display printer information",
1747 "net ads printer info\n"
1748 " Display printer information"
1751 "publish",
1752 net_ads_printer_publish,
1753 NET_TRANSPORT_ADS,
1754 "Publish a printer",
1755 "net ads printer publish\n"
1756 " Publish a printer"
1759 "remove",
1760 net_ads_printer_remove,
1761 NET_TRANSPORT_ADS,
1762 "Delete a printer",
1763 "net ads printer remove\n"
1764 " Delete a printer"
1766 {NULL, NULL, 0, NULL, NULL}
1769 return net_run_function3(c, argc, argv, "net ads printer", func);
1773 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1775 ADS_STRUCT *ads;
1776 const char *auth_principal = c->opt_user_name;
1777 const char *auth_password = c->opt_password;
1778 char *realm = NULL;
1779 char *new_password = NULL;
1780 char *chr, *prompt;
1781 const char *user;
1782 ADS_STATUS ret;
1784 if (c->display_usage) {
1785 d_printf("Usage:\n"
1786 "net ads password <username>\n"
1787 " Change password for user\n"
1788 " username\tName of user to change password for\n");
1789 return 0;
1792 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1793 d_fprintf(stderr, "You must supply an administrator username/password\n");
1794 return -1;
1797 if (argc < 1) {
1798 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1799 return -1;
1802 user = argv[0];
1803 if (!strchr_m(user, '@')) {
1804 asprintf(&chr, "%s@%s", argv[0], lp_realm());
1805 user = chr;
1808 use_in_memory_ccache();
1809 chr = strchr_m(auth_principal, '@');
1810 if (chr) {
1811 realm = ++chr;
1812 } else {
1813 realm = lp_realm();
1816 /* use the realm so we can eventually change passwords for users
1817 in realms other than default */
1818 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1819 return -1;
1822 /* we don't actually need a full connect, but it's the easy way to
1823 fill in the KDC's addresss */
1824 ads_connect(ads);
1826 if (!ads->config.realm) {
1827 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1828 return -1;
1831 if (argv[1]) {
1832 new_password = (char *)argv[1];
1833 } else {
1834 asprintf(&prompt, "Enter new password for %s:", user);
1835 new_password = getpass(prompt);
1836 free(prompt);
1839 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1840 auth_password, user, new_password, ads->auth.time_offset);
1841 if (!ADS_ERR_OK(ret)) {
1842 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1843 ads_destroy(&ads);
1844 return -1;
1847 d_printf("Password change for %s completed.\n", user);
1848 ads_destroy(&ads);
1850 return 0;
1853 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1855 ADS_STRUCT *ads;
1856 char *host_principal;
1857 fstring my_name;
1858 ADS_STATUS ret;
1860 if (c->display_usage) {
1861 d_printf("Usage:\n"
1862 "net ads changetrustpw\n"
1863 " Change the machine account's trust password\n");
1864 return 0;
1867 if (!secrets_init()) {
1868 DEBUG(1,("Failed to initialise secrets database\n"));
1869 return -1;
1872 net_use_krb_machine_account(c);
1874 use_in_memory_ccache();
1876 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1877 return -1;
1880 fstrcpy(my_name, global_myname());
1881 strlower_m(my_name);
1882 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1883 d_printf("Changing password for principal: %s\n", host_principal);
1885 ret = ads_change_trust_account_password(ads, host_principal);
1887 if (!ADS_ERR_OK(ret)) {
1888 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1889 ads_destroy(&ads);
1890 SAFE_FREE(host_principal);
1891 return -1;
1894 d_printf("Password change for principal %s succeeded.\n", host_principal);
1896 if (lp_use_kerberos_keytab()) {
1897 d_printf("Attempting to update system keytab with new password.\n");
1898 if (ads_keytab_create_default(ads)) {
1899 d_printf("Failed to update system keytab.\n");
1903 ads_destroy(&ads);
1904 SAFE_FREE(host_principal);
1906 return 0;
1910 help for net ads search
1912 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
1914 d_printf(
1915 "\nnet ads search <expression> <attributes...>\n"
1916 "\nperform a raw LDAP search on a ADS server and dump the results\n"
1917 "The expression is a standard LDAP search expression, and the\n"
1918 "attributes are a list of LDAP fields to show in the results\n\n"
1919 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1921 net_common_flags_usage(c, argc, argv);
1922 return -1;
1927 general ADS search function. Useful in diagnosing problems in ADS
1929 static int net_ads_search(struct net_context *c, int argc, const char **argv)
1931 ADS_STRUCT *ads;
1932 ADS_STATUS rc;
1933 const char *ldap_exp;
1934 const char **attrs;
1935 LDAPMessage *res = NULL;
1937 if (argc < 1 || c->display_usage) {
1938 return net_ads_search_usage(c, argc, argv);
1941 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1942 return -1;
1945 ldap_exp = argv[0];
1946 attrs = (argv + 1);
1948 rc = ads_do_search_all(ads, ads->config.bind_path,
1949 LDAP_SCOPE_SUBTREE,
1950 ldap_exp, attrs, &res);
1951 if (!ADS_ERR_OK(rc)) {
1952 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1953 ads_destroy(&ads);
1954 return -1;
1957 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1959 /* dump the results */
1960 ads_dump(ads, res);
1962 ads_msgfree(ads, res);
1963 ads_destroy(&ads);
1965 return 0;
1970 help for net ads search
1972 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
1974 d_printf(
1975 "\nnet ads dn <dn> <attributes...>\n"
1976 "\nperform a raw LDAP search on a ADS server and dump the results\n"
1977 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
1978 "to show in the results\n\n"
1979 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1980 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1982 net_common_flags_usage(c, argc, argv);
1983 return -1;
1988 general ADS search function. Useful in diagnosing problems in ADS
1990 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
1992 ADS_STRUCT *ads;
1993 ADS_STATUS rc;
1994 const char *dn;
1995 const char **attrs;
1996 LDAPMessage *res = NULL;
1998 if (argc < 1 || c->display_usage) {
1999 return net_ads_dn_usage(c, argc, argv);
2002 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2003 return -1;
2006 dn = argv[0];
2007 attrs = (argv + 1);
2009 rc = ads_do_search_all(ads, dn,
2010 LDAP_SCOPE_BASE,
2011 "(objectclass=*)", attrs, &res);
2012 if (!ADS_ERR_OK(rc)) {
2013 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2014 ads_destroy(&ads);
2015 return -1;
2018 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2020 /* dump the results */
2021 ads_dump(ads, res);
2023 ads_msgfree(ads, res);
2024 ads_destroy(&ads);
2026 return 0;
2030 help for net ads sid search
2032 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2034 d_printf(
2035 "\nnet ads sid <sid> <attributes...>\n"
2036 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2037 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2038 "to show in the results\n\n"
2039 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2041 net_common_flags_usage(c, argc, argv);
2042 return -1;
2047 general ADS search function. Useful in diagnosing problems in ADS
2049 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2051 ADS_STRUCT *ads;
2052 ADS_STATUS rc;
2053 const char *sid_string;
2054 const char **attrs;
2055 LDAPMessage *res = NULL;
2056 DOM_SID sid;
2058 if (argc < 1 || c->display_usage) {
2059 return net_ads_sid_usage(c, argc, argv);
2062 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2063 return -1;
2066 sid_string = argv[0];
2067 attrs = (argv + 1);
2069 if (!string_to_sid(&sid, sid_string)) {
2070 d_fprintf(stderr, "could not convert sid\n");
2071 ads_destroy(&ads);
2072 return -1;
2075 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2076 if (!ADS_ERR_OK(rc)) {
2077 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2078 ads_destroy(&ads);
2079 return -1;
2082 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2084 /* dump the results */
2085 ads_dump(ads, res);
2087 ads_msgfree(ads, res);
2088 ads_destroy(&ads);
2090 return 0;
2093 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2095 int ret;
2096 ADS_STRUCT *ads;
2098 if (c->display_usage) {
2099 d_printf("Usage:\n"
2100 "net ads keytab flush\n"
2101 " Delete the whole keytab\n");
2102 return 0;
2105 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2106 return -1;
2108 ret = ads_keytab_flush(ads);
2109 ads_destroy(&ads);
2110 return ret;
2113 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2115 int i;
2116 int ret = 0;
2117 ADS_STRUCT *ads;
2119 if (c->display_usage) {
2120 d_printf("Usage:\n"
2121 "net ads keytab add <principal> [principal ...]\n"
2122 " Add principals to local keytab\n"
2123 " principal\tKerberos principal to add to "
2124 "keytab\n");
2125 return 0;
2128 d_printf("Processing principals to add...\n");
2129 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2130 return -1;
2132 for (i = 0; i < argc; i++) {
2133 ret |= ads_keytab_add_entry(ads, argv[i]);
2135 ads_destroy(&ads);
2136 return ret;
2139 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2141 ADS_STRUCT *ads;
2142 int ret;
2144 if (c->display_usage) {
2145 d_printf("Usage:\n"
2146 "net ads keytab create\n"
2147 " Create new default keytab\n");
2148 return 0;
2151 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2152 return -1;
2154 ret = ads_keytab_create_default(ads);
2155 ads_destroy(&ads);
2156 return ret;
2159 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2161 const char *keytab = NULL;
2163 if (c->display_usage) {
2164 d_printf("Usage:\n"
2165 "net ads keytab list [keytab]\n"
2166 " List a local keytab\n"
2167 " keytab\tKeytab to list\n");
2168 return 0;
2171 if (argc >= 1) {
2172 keytab = argv[0];
2175 return ads_keytab_list(keytab);
2179 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2181 struct functable3 func[] = {
2183 "add",
2184 net_ads_keytab_add,
2185 NET_TRANSPORT_ADS,
2186 "Add a service principal",
2187 "net ads keytab add\n"
2188 " Add a service principal"
2191 "create",
2192 net_ads_keytab_create,
2193 NET_TRANSPORT_ADS,
2194 "Create a fresh keytab",
2195 "net ads keytab create\n"
2196 " Create a fresh keytab"
2199 "flush",
2200 net_ads_keytab_flush,
2201 NET_TRANSPORT_ADS,
2202 "Remove all keytab entries",
2203 "net ads keytab flush\n"
2204 " Remove all keytab entries"
2207 "list",
2208 net_ads_keytab_list,
2209 NET_TRANSPORT_ADS,
2210 "List a keytab",
2211 "net ads keytab list\n"
2212 " List a keytab"
2214 {NULL, NULL, 0, NULL, NULL}
2217 if (!lp_use_kerberos_keytab()) {
2218 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2219 use keytab functions.\n");
2222 return net_run_function3(c, argc, argv, "net ads keytab", func);
2225 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2227 int ret = -1;
2229 if (c->display_usage) {
2230 d_printf("Usage:\n"
2231 "net ads kerberos renew\n"
2232 " Renew TGT from existing credential cache\n");
2233 return 0;
2236 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2237 if (ret) {
2238 d_printf("failed to renew kerberos ticket: %s\n",
2239 error_message(ret));
2241 return ret;
2244 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2246 struct PAC_DATA *pac = NULL;
2247 struct PAC_LOGON_INFO *info = NULL;
2248 TALLOC_CTX *mem_ctx = NULL;
2249 NTSTATUS status;
2250 int ret = -1;
2252 if (c->display_usage) {
2253 d_printf("Usage:\n"
2254 "net ads kerberos pac\n"
2255 " Dump the Kerberos PAC\n");
2256 return 0;
2259 mem_ctx = talloc_init("net_ads_kerberos_pac");
2260 if (!mem_ctx) {
2261 goto out;
2264 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2266 status = kerberos_return_pac(mem_ctx,
2267 c->opt_user_name,
2268 c->opt_password,
2270 NULL,
2271 NULL,
2272 NULL,
2273 true,
2274 true,
2275 2592000, /* one month */
2276 &pac);
2277 if (!NT_STATUS_IS_OK(status)) {
2278 d_printf("failed to query kerberos PAC: %s\n",
2279 nt_errstr(status));
2280 goto out;
2283 info = get_logon_info_from_pac(pac);
2284 if (info) {
2285 const char *s;
2286 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2287 d_printf("The Pac: %s\n", s);
2290 ret = 0;
2291 out:
2292 TALLOC_FREE(mem_ctx);
2293 return ret;
2296 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2298 TALLOC_CTX *mem_ctx = NULL;
2299 int ret = -1;
2300 NTSTATUS status;
2302 if (c->display_usage) {
2303 d_printf("Usage:\n"
2304 "net ads kerberos kinit\n"
2305 " Get Ticket Granting Ticket (TGT) for the user\n");
2306 return 0;
2309 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2310 if (!mem_ctx) {
2311 goto out;
2314 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2316 ret = kerberos_kinit_password_ext(c->opt_user_name,
2317 c->opt_password,
2319 NULL,
2320 NULL,
2321 NULL,
2322 true,
2323 true,
2324 2592000, /* one month */
2325 &status);
2326 if (ret) {
2327 d_printf("failed to kinit password: %s\n",
2328 nt_errstr(status));
2330 out:
2331 return ret;
2334 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2336 struct functable3 func[] = {
2338 "kinit",
2339 net_ads_kerberos_kinit,
2340 NET_TRANSPORT_ADS,
2341 "Retrieve Ticket Granting Ticket (TGT)",
2342 "net ads kerberos kinit\n"
2343 " Receive Ticket Granting Ticket (TGT)"
2346 "renew",
2347 net_ads_kerberos_renew,
2348 NET_TRANSPORT_ADS,
2349 "Renew Ticket Granting Ticket from credential cache"
2350 "net ads kerberos renew\n"
2351 " Renew Ticket Granting Ticket from credential cache"
2354 "pac",
2355 net_ads_kerberos_pac,
2356 NET_TRANSPORT_ADS,
2357 "Dump Kerberos PAC",
2358 "net ads kerberos pac\n"
2359 " Dump Kerberos PAC"
2361 {NULL, NULL, 0, NULL, NULL}
2364 return net_run_function3(c, argc, argv, "net ads kerberos", func);
2367 int net_ads(struct net_context *c, int argc, const char **argv)
2369 struct functable3 func[] = {
2371 "info",
2372 net_ads_info,
2373 NET_TRANSPORT_ADS,
2374 "Display details on remote ADS server",
2375 "net ads info\n"
2376 " Display details on remote ADS server"
2379 "join",
2380 net_ads_join,
2381 NET_TRANSPORT_ADS,
2382 "Join the local machine to ADS realm",
2383 "net ads join\n"
2384 " Join the local machine to ADS realm"
2387 "testjoin",
2388 net_ads_testjoin,
2389 NET_TRANSPORT_ADS,
2390 "Validate machine account",
2391 "net ads testjoin\n"
2392 " Validate machine account"
2395 "leave",
2396 net_ads_leave,
2397 NET_TRANSPORT_ADS,
2398 "Remove the local machine from ADS",
2399 "net ads leave\n"
2400 " Remove the local machine from ADS"
2403 "status",
2404 net_ads_status,
2405 NET_TRANSPORT_ADS,
2406 "Display machine account details",
2407 "net ads status\n"
2408 " Display machine account details"
2411 "user",
2412 net_ads_user,
2413 NET_TRANSPORT_ADS,
2414 "List/modify users",
2415 "net ads user\n"
2416 " List/modify users"
2419 "group",
2420 net_ads_group,
2421 NET_TRANSPORT_ADS,
2422 "List/modify groups",
2423 "net ads group\n"
2424 " List/modify groups"
2427 "dns",
2428 net_ads_dns,
2429 NET_TRANSPORT_ADS,
2430 "Issue dynamic DNS update",
2431 "net ads dns\n"
2432 " Issue dynamic DNS update"
2435 "password",
2436 net_ads_password,
2437 NET_TRANSPORT_ADS,
2438 "Change user passwords",
2439 "net ads password\n"
2440 " Change user passwords"
2443 "changetrustpw",
2444 net_ads_changetrustpw,
2445 NET_TRANSPORT_ADS,
2446 "Change trust account password",
2447 "net ads changetrustpw\n"
2448 " Change trust account password"
2451 "printer",
2452 net_ads_printer,
2453 NET_TRANSPORT_ADS,
2454 "List/modify printer entries",
2455 "net ads printer\n"
2456 " List/modify printer entries"
2459 "search",
2460 net_ads_search,
2461 NET_TRANSPORT_ADS,
2462 "Issue LDAP search using filter",
2463 "net ads search\n"
2464 " Issue LDAP search using filter"
2467 "dn",
2468 net_ads_dn,
2469 NET_TRANSPORT_ADS,
2470 "Issue LDAP search by DN",
2471 "net ads dn\n"
2472 " Issue LDAP search by DN"
2475 "sid",
2476 net_ads_sid,
2477 NET_TRANSPORT_ADS,
2478 "Issue LDAP search by SID",
2479 "net ads sid\n"
2480 " Issue LDAP search by SID"
2483 "workgroup",
2484 net_ads_workgroup,
2485 NET_TRANSPORT_ADS,
2486 "Display workgroup name",
2487 "net ads workgroup\n"
2488 " Display the workgroup name"
2491 "lookup",
2492 net_ads_lookup,
2493 NET_TRANSPORT_ADS,
2494 "Perfom CLDAP query on DC",
2495 "net ads lookup\n"
2496 " Find the ADS DC using CLDAP lookups"
2499 "keytab",
2500 net_ads_keytab,
2501 NET_TRANSPORT_ADS,
2502 "Manage local keytab file",
2503 "net ads keytab\n"
2504 " Manage local keytab file"
2507 "gpo",
2508 net_ads_gpo,
2509 NET_TRANSPORT_ADS,
2510 "Manage group policy objects",
2511 "net ads gpo\n"
2512 " Manage group policy objects"
2515 "kerberos",
2516 net_ads_kerberos,
2517 NET_TRANSPORT_ADS,
2518 "Manage kerberos keytab",
2519 "net ads kerberos\n"
2520 " Manage kerberos keytab"
2522 {NULL, NULL, 0, NULL, NULL}
2525 return net_run_function3(c, argc, argv, "net ads", func);
2528 #else
2530 static int net_ads_noads(void)
2532 d_fprintf(stderr, "ADS support not compiled in\n");
2533 return -1;
2536 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2538 return net_ads_noads();
2541 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2543 return net_ads_noads();
2546 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2548 return net_ads_noads();
2551 int net_ads_join(struct net_context *c, int argc, const char **argv)
2553 return net_ads_noads();
2556 int net_ads_user(struct net_context *c, int argc, const char **argv)
2558 return net_ads_noads();
2561 int net_ads_group(struct net_context *c, int argc, const char **argv)
2563 return net_ads_noads();
2566 /* this one shouldn't display a message */
2567 int net_ads_check(struct net_context *c)
2569 return -1;
2572 int net_ads_check_our_domain(struct net_context *c)
2574 return -1;
2577 int net_ads(struct net_context *c, int argc, const char **argv)
2579 return net_ads_usage(c, argc, argv);
2582 #endif /* WITH_ADS */