net ads: Fix typos.
[Samba.git] / source3 / utils / net_ads.c
blob4d37e2bf8d55832e6f512d6d3e8180460c8cdbe7
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 /* when we do not have sufficient input parameters to contact a remote domain
29 * we always fall back to our own realm - Guenther*/
31 static const char *assume_own_realm(struct net_context *c)
33 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
34 return lp_realm();
37 return NULL;
41 do a cldap netlogon query
43 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
45 char addr[INET6_ADDRSTRLEN];
46 struct nbt_cldap_netlogon_5 reply;
48 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
49 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
50 d_fprintf(stderr, "CLDAP query failed!\n");
51 return -1;
54 d_printf("Information for Domain Controller: %s\n\n",
55 addr);
57 d_printf("Response Type: ");
58 switch (reply.type) {
59 case SAMLOGON_AD_UNK_R:
60 d_printf("SAMLOGON\n");
61 break;
62 case SAMLOGON_AD_R:
63 d_printf("SAMLOGON_USER\n");
64 break;
65 default:
66 d_printf("0x%x\n", reply.type);
67 break;
70 d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), reply.domain_uuid));
72 d_printf("Flags:\n"
73 "\tIs a PDC: %s\n"
74 "\tIs a GC of the forest: %s\n"
75 "\tIs an LDAP server: %s\n"
76 "\tSupports DS: %s\n"
77 "\tIs running a KDC: %s\n"
78 "\tIs running time services: %s\n"
79 "\tIs the closest DC: %s\n"
80 "\tIs writable: %s\n"
81 "\tHas a hardware clock: %s\n"
82 "\tIs a non-domain NC serviced by LDAP server: %s\n"
83 "\tIs NT6 DC that has some secrets: %s\n"
84 "\tIs NT6 DC that has all secrets: %s\n",
85 (reply.server_type & NBT_SERVER_PDC) ? "yes" : "no",
86 (reply.server_type & NBT_SERVER_GC) ? "yes" : "no",
87 (reply.server_type & NBT_SERVER_LDAP) ? "yes" : "no",
88 (reply.server_type & NBT_SERVER_DS) ? "yes" : "no",
89 (reply.server_type & NBT_SERVER_KDC) ? "yes" : "no",
90 (reply.server_type & NBT_SERVER_TIMESERV) ? "yes" : "no",
91 (reply.server_type & NBT_SERVER_CLOSEST) ? "yes" : "no",
92 (reply.server_type & NBT_SERVER_WRITABLE) ? "yes" : "no",
93 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? "yes" : "no",
94 (reply.server_type & NBT_SERVER_NDNC) ? "yes" : "no",
95 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? "yes" : "no",
96 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? "yes" : "no");
99 printf("Forest:\t\t\t%s\n", reply.forest);
100 printf("Domain:\t\t\t%s\n", reply.dns_domain);
101 printf("Domain Controller:\t%s\n", reply.pdc_dns_name);
103 printf("Pre-Win2k Domain:\t%s\n", reply.domain);
104 printf("Pre-Win2k Hostname:\t%s\n", reply.pdc_name);
106 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
108 printf("Server Site Name :\t\t%s\n", reply.server_site);
109 printf("Client Site Name :\t\t%s\n", reply.client_site);
111 d_printf("NT Version: %d\n", reply.nt_version);
112 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
113 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
115 return 0;
119 this implements the CLDAP based netlogon lookup requests
120 for finding the domain controller of a ADS domain
122 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
124 ADS_STRUCT *ads;
126 if (c->display_usage) {
127 d_printf("Usage:\n"
128 "net ads lookup\n"
129 " Find the ADS DC using CLDAP lookup.\n");
130 return 0;
133 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
134 d_fprintf(stderr, "Didn't find the cldap server!\n");
135 return -1;
138 if (!ads->config.realm) {
139 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
140 ads->ldap.port = 389;
143 return net_ads_cldap_netlogon(c, ads);
148 static int net_ads_info(struct net_context *c, int argc, const char **argv)
150 ADS_STRUCT *ads;
151 char addr[INET6_ADDRSTRLEN];
153 if (c->display_usage) {
154 d_printf("Usage:\n"
155 "net ads info\n"
156 " Display information about an Active Directory "
157 "server.\n");
158 return 0;
161 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
162 d_fprintf(stderr, "Didn't find the ldap server!\n");
163 return -1;
166 if (!ads || !ads->config.realm) {
167 d_fprintf(stderr, "Didn't find the ldap server!\n");
168 return -1;
171 /* Try to set the server's current time since we didn't do a full
172 TCP LDAP session initially */
174 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
175 d_fprintf( stderr, "Failed to get server's current time!\n");
178 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
180 d_printf("LDAP server: %s\n", addr);
181 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
182 d_printf("Realm: %s\n", ads->config.realm);
183 d_printf("Bind Path: %s\n", ads->config.bind_path);
184 d_printf("LDAP port: %d\n", ads->ldap.port);
185 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
187 d_printf("KDC server: %s\n", ads->auth.kdc_server );
188 d_printf("Server time offset: %d\n", ads->auth.time_offset );
190 return 0;
193 static void use_in_memory_ccache(void) {
194 /* Use in-memory credentials cache so we do not interfere with
195 * existing credentials */
196 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
199 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
200 uint32 auth_flags, ADS_STRUCT **ads_ret)
202 ADS_STRUCT *ads = NULL;
203 ADS_STATUS status;
204 bool need_password = false;
205 bool second_time = false;
206 char *cp;
207 const char *realm = NULL;
208 bool tried_closest_dc = false;
210 /* lp_realm() should be handled by a command line param,
211 However, the join requires that realm be set in smb.conf
212 and compares our realm with the remote server's so this is
213 ok until someone needs more flexibility */
215 *ads_ret = NULL;
217 retry_connect:
218 if (only_own_domain) {
219 realm = lp_realm();
220 } else {
221 realm = assume_own_realm(c);
224 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
226 if (!c->opt_user_name) {
227 c->opt_user_name = "administrator";
230 if (c->opt_user_specified) {
231 need_password = true;
234 retry:
235 if (!c->opt_password && need_password && !c->opt_machine_pass) {
236 c->opt_password = net_prompt_pass(c, c->opt_user_name);
237 if (!c->opt_password) {
238 ads_destroy(&ads);
239 return ADS_ERROR(LDAP_NO_MEMORY);
243 if (c->opt_password) {
244 use_in_memory_ccache();
245 SAFE_FREE(ads->auth.password);
246 ads->auth.password = smb_xstrdup(c->opt_password);
249 ads->auth.flags |= auth_flags;
250 SAFE_FREE(ads->auth.user_name);
251 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
254 * If the username is of the form "name@realm",
255 * extract the realm and convert to upper case.
256 * This is only used to establish the connection.
258 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
259 *cp++ = '\0';
260 SAFE_FREE(ads->auth.realm);
261 ads->auth.realm = smb_xstrdup(cp);
262 strupper_m(ads->auth.realm);
265 status = ads_connect(ads);
267 if (!ADS_ERR_OK(status)) {
269 if (NT_STATUS_EQUAL(ads_ntstatus(status),
270 NT_STATUS_NO_LOGON_SERVERS)) {
271 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
272 ads_destroy(&ads);
273 return status;
276 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
277 need_password = true;
278 second_time = true;
279 goto retry;
280 } else {
281 ads_destroy(&ads);
282 return status;
286 /* when contacting our own domain, make sure we use the closest DC.
287 * This is done by reconnecting to ADS because only the first call to
288 * ads_connect will give us our own sitename */
290 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
292 tried_closest_dc = true; /* avoid loop */
294 if (!ads->config.tried_closest_dc) {
296 namecache_delete(ads->server.realm, 0x1C);
297 namecache_delete(ads->server.workgroup, 0x1C);
299 ads_destroy(&ads);
300 ads = NULL;
302 goto retry_connect;
306 *ads_ret = ads;
307 return status;
310 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
312 return ads_startup_int(c, only_own_domain, 0, ads);
315 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
317 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
321 Check to see if connection can be made via ads.
322 ads_startup() stores the password in opt_password if it needs to so
323 that rpc or rap can use it without re-prompting.
325 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
327 ADS_STRUCT *ads;
328 ADS_STATUS status;
330 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
331 return -1;
334 ads->auth.flags |= ADS_AUTH_NO_BIND;
336 status = ads_connect(ads);
337 if ( !ADS_ERR_OK(status) ) {
338 return -1;
341 ads_destroy(&ads);
342 return 0;
345 int net_ads_check_our_domain(struct net_context *c)
347 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
350 int net_ads_check(struct net_context *c)
352 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
356 determine the netbios workgroup name for a domain
358 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
360 ADS_STRUCT *ads;
361 char addr[INET6_ADDRSTRLEN];
362 struct nbt_cldap_netlogon_5 reply;
364 if (c->display_usage) {
365 d_printf("Usage:\n"
366 "net ads workgroup\n"
367 " Print the workgroup name\n");
368 return 0;
371 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
372 d_fprintf(stderr, "Didn't find the cldap server!\n");
373 return -1;
376 if (!ads->config.realm) {
377 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
378 ads->ldap.port = 389;
381 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
382 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
383 d_fprintf(stderr, "CLDAP query failed!\n");
384 return -1;
387 d_printf("Workgroup: %s\n", reply.domain);
389 ads_destroy(&ads);
391 return 0;
396 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
398 char **disp_fields = (char **) data_area;
400 if (!field) { /* must be end of record */
401 if (disp_fields[0]) {
402 if (!strchr_m(disp_fields[0], '$')) {
403 if (disp_fields[1])
404 d_printf("%-21.21s %s\n",
405 disp_fields[0], disp_fields[1]);
406 else
407 d_printf("%s\n", disp_fields[0]);
410 SAFE_FREE(disp_fields[0]);
411 SAFE_FREE(disp_fields[1]);
412 return true;
414 if (!values) /* must be new field, indicate string field */
415 return true;
416 if (StrCaseCmp(field, "sAMAccountName") == 0) {
417 disp_fields[0] = SMB_STRDUP((char *) values[0]);
419 if (StrCaseCmp(field, "description") == 0)
420 disp_fields[1] = SMB_STRDUP((char *) values[0]);
421 return true;
424 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
426 return net_user_usage(c, argc, argv);
429 static int ads_user_add(struct net_context *c, int argc, const char **argv)
431 ADS_STRUCT *ads;
432 ADS_STATUS status;
433 char *upn, *userdn;
434 LDAPMessage *res=NULL;
435 int rc = -1;
436 char *ou_str = NULL;
438 if (argc < 1 || c->display_usage)
439 return net_ads_user_usage(c, argc, argv);
441 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
442 return -1;
445 status = ads_find_user_acct(ads, &res, argv[0]);
447 if (!ADS_ERR_OK(status)) {
448 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
449 goto done;
452 if (ads_count_replies(ads, res)) {
453 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
454 goto done;
457 if (c->opt_container) {
458 ou_str = SMB_STRDUP(c->opt_container);
459 } else {
460 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
463 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
465 if (!ADS_ERR_OK(status)) {
466 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
467 ads_errstr(status));
468 goto done;
471 /* if no password is to be set, we're done */
472 if (argc == 1) {
473 d_printf("User %s added\n", argv[0]);
474 rc = 0;
475 goto done;
478 /* try setting the password */
479 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
480 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
481 ads->auth.time_offset);
482 safe_free(upn);
483 if (ADS_ERR_OK(status)) {
484 d_printf("User %s added\n", argv[0]);
485 rc = 0;
486 goto done;
489 /* password didn't set, delete account */
490 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
491 argv[0], ads_errstr(status));
492 ads_msgfree(ads, res);
493 status=ads_find_user_acct(ads, &res, argv[0]);
494 if (ADS_ERR_OK(status)) {
495 userdn = ads_get_dn(ads, res);
496 ads_del_dn(ads, userdn);
497 ads_memfree(ads, userdn);
500 done:
501 if (res)
502 ads_msgfree(ads, res);
503 ads_destroy(&ads);
504 SAFE_FREE(ou_str);
505 return rc;
508 static int ads_user_info(struct net_context *c, int argc, const char **argv)
510 ADS_STRUCT *ads;
511 ADS_STATUS rc;
512 LDAPMessage *res;
513 const char *attrs[] = {"memberOf", NULL};
514 char *searchstring=NULL;
515 char **grouplist;
516 char *escaped_user;
518 if (argc < 1 || c->display_usage) {
519 return net_ads_user_usage(c, argc, argv);
522 escaped_user = escape_ldap_string_alloc(argv[0]);
524 if (!escaped_user) {
525 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
526 return -1;
529 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
530 SAFE_FREE(escaped_user);
531 return -1;
534 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
535 rc = ads_search(ads, &res, searchstring, attrs);
536 safe_free(searchstring);
538 if (!ADS_ERR_OK(rc)) {
539 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
540 ads_destroy(&ads);
541 SAFE_FREE(escaped_user);
542 return -1;
545 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
546 (LDAPMessage *)res, "memberOf");
548 if (grouplist) {
549 int i;
550 char **groupname;
551 for (i=0;grouplist[i];i++) {
552 groupname = ldap_explode_dn(grouplist[i], 1);
553 d_printf("%s\n", groupname[0]);
554 ldap_value_free(groupname);
556 ldap_value_free(grouplist);
559 ads_msgfree(ads, res);
560 ads_destroy(&ads);
561 SAFE_FREE(escaped_user);
562 return 0;
565 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
567 ADS_STRUCT *ads;
568 ADS_STATUS rc;
569 LDAPMessage *res = NULL;
570 char *userdn;
572 if (argc < 1) {
573 return net_ads_user_usage(c, argc, argv);
576 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
577 return -1;
580 rc = ads_find_user_acct(ads, &res, argv[0]);
581 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
582 d_printf("User %s does not exist.\n", argv[0]);
583 ads_msgfree(ads, res);
584 ads_destroy(&ads);
585 return -1;
587 userdn = ads_get_dn(ads, res);
588 ads_msgfree(ads, res);
589 rc = ads_del_dn(ads, userdn);
590 ads_memfree(ads, userdn);
591 if (ADS_ERR_OK(rc)) {
592 d_printf("User %s deleted\n", argv[0]);
593 ads_destroy(&ads);
594 return 0;
596 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
597 ads_errstr(rc));
598 ads_destroy(&ads);
599 return -1;
602 int net_ads_user(struct net_context *c, int argc, const char **argv)
604 struct functable func[] = {
606 "add",
607 ads_user_add,
608 NET_TRANSPORT_ADS,
609 "Add an AD user",
610 "net ads user add\n"
611 " Add an AD user"
614 "info",
615 ads_user_info,
616 NET_TRANSPORT_ADS,
617 "Display information about an AD user",
618 "net ads user info\n"
619 " Display information about an AD user"
622 "delete",
623 ads_user_delete,
624 NET_TRANSPORT_ADS,
625 "Delete an AD user",
626 "net ads user delete\n"
627 " Delete an AD user"
629 {NULL, NULL, 0, NULL, NULL}
631 ADS_STRUCT *ads;
632 ADS_STATUS rc;
633 const char *shortattrs[] = {"sAMAccountName", NULL};
634 const char *longattrs[] = {"sAMAccountName", "description", NULL};
635 char *disp_fields[2] = {NULL, NULL};
637 if (argc == 0) {
638 if (c->display_usage) {
639 d_printf("Usage:\n");
640 d_printf("net ads user\n"
641 " List AD users\n");
642 net_display_usage_from_functable(func);
643 return 0;
646 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
647 return -1;
650 if (c->opt_long_list_entries)
651 d_printf("\nUser name Comment"
652 "\n-----------------------------\n");
654 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
655 LDAP_SCOPE_SUBTREE,
656 "(objectCategory=user)",
657 c->opt_long_list_entries ? longattrs :
658 shortattrs, usergrp_display,
659 disp_fields);
660 ads_destroy(&ads);
661 return ADS_ERR_OK(rc) ? 0 : -1;
664 return net_run_function(c, argc, argv, "net ads user", func);
667 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
669 return net_group_usage(c, argc, argv);
672 static int ads_group_add(struct net_context *c, int argc, const char **argv)
674 ADS_STRUCT *ads;
675 ADS_STATUS status;
676 LDAPMessage *res=NULL;
677 int rc = -1;
678 char *ou_str = NULL;
680 if (argc < 1 || c->display_usage) {
681 return net_ads_group_usage(c, argc, argv);
684 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
685 return -1;
688 status = ads_find_user_acct(ads, &res, argv[0]);
690 if (!ADS_ERR_OK(status)) {
691 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
692 goto done;
695 if (ads_count_replies(ads, res)) {
696 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
697 goto done;
700 if (c->opt_container) {
701 ou_str = SMB_STRDUP(c->opt_container);
702 } else {
703 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
706 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
708 if (ADS_ERR_OK(status)) {
709 d_printf("Group %s added\n", argv[0]);
710 rc = 0;
711 } else {
712 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
713 ads_errstr(status));
716 done:
717 if (res)
718 ads_msgfree(ads, res);
719 ads_destroy(&ads);
720 SAFE_FREE(ou_str);
721 return rc;
724 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
726 ADS_STRUCT *ads;
727 ADS_STATUS rc;
728 LDAPMessage *res = NULL;
729 char *groupdn;
731 if (argc < 1 || c->display_usage) {
732 return net_ads_group_usage(c, argc, argv);
735 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
736 return -1;
739 rc = ads_find_user_acct(ads, &res, argv[0]);
740 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
741 d_printf("Group %s does not exist.\n", argv[0]);
742 ads_msgfree(ads, res);
743 ads_destroy(&ads);
744 return -1;
746 groupdn = ads_get_dn(ads, res);
747 ads_msgfree(ads, res);
748 rc = ads_del_dn(ads, groupdn);
749 ads_memfree(ads, groupdn);
750 if (ADS_ERR_OK(rc)) {
751 d_printf("Group %s deleted\n", argv[0]);
752 ads_destroy(&ads);
753 return 0;
755 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
756 ads_errstr(rc));
757 ads_destroy(&ads);
758 return -1;
761 int net_ads_group(struct net_context *c, int argc, const char **argv)
763 struct functable func[] = {
765 "add",
766 ads_group_add,
767 NET_TRANSPORT_ADS,
768 "Add an AD group",
769 "net ads group add\n"
770 " Add an AD group"
773 "delete",
774 ads_group_delete,
775 NET_TRANSPORT_ADS,
776 "Delete an AD group",
777 "net ads group delete\n"
778 " Delete an AD group"
780 {NULL, NULL, 0, NULL, NULL}
782 ADS_STRUCT *ads;
783 ADS_STATUS rc;
784 const char *shortattrs[] = {"sAMAccountName", NULL};
785 const char *longattrs[] = {"sAMAccountName", "description", NULL};
786 char *disp_fields[2] = {NULL, NULL};
788 if (argc == 0) {
789 if (c->display_usage) {
790 d_printf("Usage:\n");
791 d_printf("net ads group\n"
792 " List AD groups\n");
793 net_display_usage_from_functable(func);
794 return 0;
797 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
798 return -1;
801 if (c->opt_long_list_entries)
802 d_printf("\nGroup name Comment"
803 "\n-----------------------------\n");
804 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
805 LDAP_SCOPE_SUBTREE,
806 "(objectCategory=group)",
807 c->opt_long_list_entries ? longattrs :
808 shortattrs, usergrp_display,
809 disp_fields);
811 ads_destroy(&ads);
812 return ADS_ERR_OK(rc) ? 0 : -1;
814 return net_run_function(c, argc, argv, "net ads group", func);
817 static int net_ads_status(struct net_context *c, int argc, const char **argv)
819 ADS_STRUCT *ads;
820 ADS_STATUS rc;
821 LDAPMessage *res;
823 if (c->display_usage) {
824 d_printf("Usage:\n"
825 "net ads status\n"
826 " Display machine account details\n");
827 return 0;
830 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
831 return -1;
834 rc = ads_find_machine_acct(ads, &res, global_myname());
835 if (!ADS_ERR_OK(rc)) {
836 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
837 ads_destroy(&ads);
838 return -1;
841 if (ads_count_replies(ads, res) == 0) {
842 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
843 ads_destroy(&ads);
844 return -1;
847 ads_dump(ads, res);
848 ads_destroy(&ads);
849 return 0;
852 /*******************************************************************
853 Leave an AD domain. Windows XP disables the machine account.
854 We'll try the same. The old code would do an LDAP delete.
855 That only worked using the machine creds because added the machine
856 with full control to the computer object's ACL.
857 *******************************************************************/
859 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
861 TALLOC_CTX *ctx;
862 struct libnet_UnjoinCtx *r = NULL;
863 WERROR werr;
865 if (c->display_usage) {
866 d_printf("Usage:\n"
867 "net ads leave\n"
868 " Leave an AD domain\n");
869 return 0;
872 if (!*lp_realm()) {
873 d_fprintf(stderr, "No realm set, are we joined ?\n");
874 return -1;
877 if (!(ctx = talloc_init("net_ads_leave"))) {
878 d_fprintf(stderr, "Could not initialise talloc context.\n");
879 return -1;
882 use_in_memory_ccache();
884 werr = libnet_init_UnjoinCtx(ctx, &r);
885 if (!W_ERROR_IS_OK(werr)) {
886 d_fprintf(stderr, "Could not initialise unjoin context.\n");
887 return -1;
890 r->in.debug = true;
891 r->in.dc_name = c->opt_host;
892 r->in.domain_name = lp_realm();
893 r->in.admin_account = c->opt_user_name;
894 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
895 r->in.modify_config = lp_config_backend_is_registry();
896 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
897 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
899 werr = libnet_Unjoin(ctx, r);
900 if (!W_ERROR_IS_OK(werr)) {
901 d_printf("Failed to leave domain: %s\n",
902 r->out.error_string ? r->out.error_string :
903 get_friendly_werror_msg(werr));
904 goto done;
907 if (W_ERROR_IS_OK(werr)) {
908 d_printf("Deleted account for '%s' in realm '%s'\n",
909 r->in.machine_name, r->out.dns_domain_name);
910 goto done;
913 /* We couldn't delete it - see if the disable succeeded. */
914 if (r->out.disabled_machine_account) {
915 d_printf("Disabled account for '%s' in realm '%s'\n",
916 r->in.machine_name, r->out.dns_domain_name);
917 werr = WERR_OK;
918 goto done;
921 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
922 r->in.machine_name, r->out.dns_domain_name);
924 done:
925 TALLOC_FREE(r);
926 TALLOC_FREE(ctx);
928 if (W_ERROR_IS_OK(werr)) {
929 return 0;
932 return -1;
935 static NTSTATUS net_ads_join_ok(struct net_context *c)
937 ADS_STRUCT *ads = NULL;
938 ADS_STATUS status;
940 if (!secrets_init()) {
941 DEBUG(1,("Failed to initialise secrets database\n"));
942 return NT_STATUS_ACCESS_DENIED;
945 net_use_krb_machine_account(c);
947 status = ads_startup(c, true, &ads);
948 if (!ADS_ERR_OK(status)) {
949 return ads_ntstatus(status);
952 ads_destroy(&ads);
953 return NT_STATUS_OK;
957 check that an existing join is OK
959 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
961 NTSTATUS status;
962 use_in_memory_ccache();
964 if (c->display_usage) {
965 d_printf("Usage:\n"
966 "net ads testjoin\n"
967 " Test if the existing join is ok\n");
968 return 0;
971 /* Display success or failure */
972 status = net_ads_join_ok(c);
973 if (!NT_STATUS_IS_OK(status)) {
974 fprintf(stderr,"Join to domain is not valid: %s\n",
975 get_friendly_nt_error_msg(status));
976 return -1;
979 printf("Join is OK\n");
980 return 0;
983 /*******************************************************************
984 Simple configu checks before beginning the join
985 ********************************************************************/
987 static WERROR check_ads_config( void )
989 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
990 d_printf("Host is not configured as a member server.\n");
991 return WERR_INVALID_DOMAIN_ROLE;
994 if (strlen(global_myname()) > 15) {
995 d_printf("Our netbios name can be at most 15 chars long, "
996 "\"%s\" is %u chars long\n", global_myname(),
997 (unsigned int)strlen(global_myname()));
998 return WERR_INVALID_COMPUTER_NAME;
1001 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1002 d_fprintf(stderr, "realm must be set in in %s for ADS "
1003 "join to succeed.\n", get_dyn_CONFIGFILE());
1004 return WERR_INVALID_PARAM;
1007 return WERR_OK;
1010 /*******************************************************************
1011 Send a DNS update request
1012 *******************************************************************/
1014 #if defined(WITH_DNS_UPDATES)
1015 #include "dns.h"
1016 DNS_ERROR DoDNSUpdate(char *pszServerName,
1017 const char *pszDomainName, const char *pszHostName,
1018 const struct sockaddr_storage *sslist,
1019 size_t num_addrs );
1021 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1022 const char *machine_name,
1023 const struct sockaddr_storage *addrs,
1024 int num_addrs)
1026 struct dns_rr_ns *nameservers = NULL;
1027 int ns_count = 0;
1028 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1029 DNS_ERROR dns_err;
1030 fstring dns_server;
1031 const char *dnsdomain = NULL;
1032 char *root_domain = NULL;
1034 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1035 d_printf("No DNS domain configured for %s. "
1036 "Unable to perform DNS Update.\n", machine_name);
1037 status = NT_STATUS_INVALID_PARAMETER;
1038 goto done;
1040 dnsdomain++;
1042 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1043 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1044 /* Child domains often do not have NS records. Look
1045 for the NS record for the forest root domain
1046 (rootDomainNamingContext in therootDSE) */
1048 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1049 LDAPMessage *msg = NULL;
1050 char *root_dn;
1051 ADS_STATUS ads_status;
1053 if ( !ads->ldap.ld ) {
1054 ads_status = ads_connect( ads );
1055 if ( !ADS_ERR_OK(ads_status) ) {
1056 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1057 goto done;
1061 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1062 "(objectclass=*)", rootname_attrs, &msg);
1063 if (!ADS_ERR_OK(ads_status)) {
1064 goto done;
1067 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1068 if ( !root_dn ) {
1069 ads_msgfree( ads, msg );
1070 goto done;
1073 root_domain = ads_build_domain( root_dn );
1075 /* cleanup */
1076 ads_msgfree( ads, msg );
1078 /* try again for NS servers */
1080 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1082 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1083 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1084 "realm\n", ads->config.realm));
1085 goto done;
1088 dnsdomain = root_domain;
1092 /* Now perform the dns update - we'll try non-secure and if we fail,
1093 we'll follow it up with a secure update */
1095 fstrcpy( dns_server, nameservers[0].hostname );
1097 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1098 if (!ERR_DNS_IS_OK(dns_err)) {
1099 status = NT_STATUS_UNSUCCESSFUL;
1102 done:
1104 SAFE_FREE( root_domain );
1106 return status;
1109 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1111 int num_addrs;
1112 struct sockaddr_storage *iplist = NULL;
1113 fstring machine_name;
1114 NTSTATUS status;
1116 name_to_fqdn( machine_name, global_myname() );
1117 strlower_m( machine_name );
1119 /* Get our ip address (not the 127.0.0.x address but a real ip
1120 * address) */
1122 num_addrs = get_my_ip_address( &iplist );
1123 if ( num_addrs <= 0 ) {
1124 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1125 "addresses!\n"));
1126 return NT_STATUS_INVALID_PARAMETER;
1129 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1130 iplist, num_addrs);
1131 SAFE_FREE( iplist );
1132 return status;
1134 #endif
1137 /*******************************************************************
1138 ********************************************************************/
1140 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1142 d_printf("net ads join [options]\n");
1143 d_printf("Valid options:\n");
1144 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1145 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1146 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1147 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1148 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1149 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1150 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1151 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1152 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1153 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1154 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1155 d_printf(" the two other attributes.\n");
1157 return -1;
1160 /*******************************************************************
1161 ********************************************************************/
1163 int net_ads_join(struct net_context *c, int argc, const char **argv)
1165 TALLOC_CTX *ctx = NULL;
1166 struct libnet_JoinCtx *r = NULL;
1167 const char *domain = lp_realm();
1168 WERROR werr = WERR_SETUP_NOT_JOINED;
1169 bool createupn = false;
1170 const char *machineupn = NULL;
1171 const char *create_in_ou = NULL;
1172 int i;
1173 const char *os_name = NULL;
1174 const char *os_version = NULL;
1175 bool modify_config = lp_config_backend_is_registry();
1177 if (c->display_usage)
1178 return net_ads_join_usage(c, argc, argv);
1180 if (!modify_config) {
1182 werr = check_ads_config();
1183 if (!W_ERROR_IS_OK(werr)) {
1184 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1185 goto fail;
1189 if (!(ctx = talloc_init("net_ads_join"))) {
1190 d_fprintf(stderr, "Could not initialise talloc context.\n");
1191 werr = WERR_NOMEM;
1192 goto fail;
1195 use_in_memory_ccache();
1197 werr = libnet_init_JoinCtx(ctx, &r);
1198 if (!W_ERROR_IS_OK(werr)) {
1199 goto fail;
1202 /* process additional command line args */
1204 for ( i=0; i<argc; i++ ) {
1205 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1206 createupn = true;
1207 machineupn = get_string_param(argv[i]);
1209 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1210 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1211 d_fprintf(stderr, "Please supply a valid OU path.\n");
1212 werr = WERR_INVALID_PARAM;
1213 goto fail;
1216 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1217 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1218 d_fprintf(stderr, "Please supply a operating system name.\n");
1219 werr = WERR_INVALID_PARAM;
1220 goto fail;
1223 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1224 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1225 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1226 werr = WERR_INVALID_PARAM;
1227 goto fail;
1230 else {
1231 domain = argv[i];
1235 if (!*domain) {
1236 d_fprintf(stderr, "Please supply a valid domain name\n");
1237 werr = WERR_INVALID_PARAM;
1238 goto fail;
1241 /* Do the domain join here */
1243 r->in.domain_name = domain;
1244 r->in.create_upn = createupn;
1245 r->in.upn = machineupn;
1246 r->in.account_ou = create_in_ou;
1247 r->in.os_name = os_name;
1248 r->in.os_version = os_version;
1249 r->in.dc_name = c->opt_host;
1250 r->in.admin_account = c->opt_user_name;
1251 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1252 r->in.debug = true;
1253 r->in.modify_config = modify_config;
1254 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1255 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1256 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1258 werr = libnet_Join(ctx, r);
1259 if (!W_ERROR_IS_OK(werr)) {
1260 goto fail;
1263 /* Check the short name of the domain */
1265 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1266 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1267 d_printf("domain name obtained from the server.\n");
1268 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1269 d_printf("You should set \"workgroup = %s\" in %s.\n",
1270 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1273 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1275 if (r->out.dns_domain_name) {
1276 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1277 r->out.dns_domain_name);
1278 } else {
1279 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1280 r->out.netbios_domain_name);
1283 #if defined(WITH_DNS_UPDATES)
1284 if (r->out.domain_is_ad) {
1285 /* We enter this block with user creds */
1286 ADS_STRUCT *ads_dns = NULL;
1288 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1289 /* kinit with the machine password */
1291 use_in_memory_ccache();
1292 asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1293 ads_dns->auth.password = secrets_fetch_machine_password(
1294 r->out.netbios_domain_name, NULL, NULL );
1295 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1296 strupper_m(ads_dns->auth.realm );
1297 ads_kinit_password( ads_dns );
1300 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1301 d_fprintf( stderr, "DNS update failed!\n" );
1304 /* exit from this block using machine creds */
1305 ads_destroy(&ads_dns);
1307 #endif
1308 TALLOC_FREE(r);
1309 TALLOC_FREE( ctx );
1311 return 0;
1313 fail:
1314 /* issue an overall failure message at the end. */
1315 d_printf("Failed to join domain: %s\n",
1316 r && r->out.error_string ? r->out.error_string :
1317 get_friendly_werror_msg(werr));
1318 TALLOC_FREE( ctx );
1320 return -1;
1323 /*******************************************************************
1324 ********************************************************************/
1326 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1328 #if defined(WITH_DNS_UPDATES)
1329 ADS_STRUCT *ads;
1330 ADS_STATUS status;
1331 TALLOC_CTX *ctx;
1333 #ifdef DEVELOPER
1334 talloc_enable_leak_report();
1335 #endif
1337 if (argc > 0 || c->display_usage) {
1338 d_printf("Usage:\n"
1339 "net ads dns register\n"
1340 " Register hostname with DNS\n");
1341 return -1;
1344 if (!(ctx = talloc_init("net_ads_dns"))) {
1345 d_fprintf(stderr, "Could not initialise talloc context\n");
1346 return -1;
1349 status = ads_startup(c, true, &ads);
1350 if ( !ADS_ERR_OK(status) ) {
1351 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1352 TALLOC_FREE(ctx);
1353 return -1;
1356 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1357 d_fprintf( stderr, "DNS update failed!\n" );
1358 ads_destroy( &ads );
1359 TALLOC_FREE( ctx );
1360 return -1;
1363 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1365 ads_destroy(&ads);
1366 TALLOC_FREE( ctx );
1368 return 0;
1369 #else
1370 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1371 return -1;
1372 #endif
1375 #if defined(WITH_DNS_UPDATES)
1376 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1377 #endif
1379 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1381 #if defined(WITH_DNS_UPDATES)
1382 DNS_ERROR err;
1384 #ifdef DEVELOPER
1385 talloc_enable_leak_report();
1386 #endif
1388 if (argc != 2 || c->display_usage) {
1389 d_printf("Usage:\n"
1390 "net ads dns gethostbyname <server> <name>\n"
1391 " Look up hostname from the AD\n"
1392 " server\tName server to use\n"
1393 " name\tName to look up\n");
1394 return -1;
1397 err = do_gethostbyname(argv[0], argv[1]);
1399 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1400 #endif
1401 return 0;
1404 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1406 struct functable func[] = {
1408 "register",
1409 net_ads_dns_register,
1410 NET_TRANSPORT_ADS,
1411 "Add host dns entry to AD",
1412 "net ads dns register\n"
1413 " Add host dns entry to AD"
1416 "gethostbyname",
1417 net_ads_dns_gethostbyname,
1418 NET_TRANSPORT_ADS,
1419 "Look up host",
1420 "net ads dns gethostbyname\n"
1421 " Look up host"
1423 {NULL, NULL, 0, NULL, NULL}
1426 return net_run_function(c, argc, argv, "net ads dns", func);
1429 /*******************************************************************
1430 ********************************************************************/
1432 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1434 d_printf(
1435 "\nnet ads printer search <printer>"
1436 "\n\tsearch for a printer in the directory\n"
1437 "\nnet ads printer info <printer> <server>"
1438 "\n\tlookup info in directory for printer on server"
1439 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1440 "\nnet ads printer publish <printername>"
1441 "\n\tpublish printer in directory"
1442 "\n\t(note: printer name is required)\n"
1443 "\nnet ads printer remove <printername>"
1444 "\n\tremove printer from directory"
1445 "\n\t(note: printer name is required)\n");
1446 return -1;
1449 /*******************************************************************
1450 ********************************************************************/
1452 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1454 ADS_STRUCT *ads;
1455 ADS_STATUS rc;
1456 LDAPMessage *res = NULL;
1458 if (c->display_usage) {
1459 d_printf("Usage:\n"
1460 "net ads printer search\n"
1461 " List printers in the AD\n");
1462 return 0;
1465 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1466 return -1;
1469 rc = ads_find_printers(ads, &res);
1471 if (!ADS_ERR_OK(rc)) {
1472 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1473 ads_msgfree(ads, res);
1474 ads_destroy(&ads);
1475 return -1;
1478 if (ads_count_replies(ads, res) == 0) {
1479 d_fprintf(stderr, "No results found\n");
1480 ads_msgfree(ads, res);
1481 ads_destroy(&ads);
1482 return -1;
1485 ads_dump(ads, res);
1486 ads_msgfree(ads, res);
1487 ads_destroy(&ads);
1488 return 0;
1491 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1493 ADS_STRUCT *ads;
1494 ADS_STATUS rc;
1495 const char *servername, *printername;
1496 LDAPMessage *res = NULL;
1498 if (c->display_usage) {
1499 d_printf("Usage:\n"
1500 "net ads printer info [printername [servername]]\n"
1501 " Display printer info from AD\n"
1502 " printername\tPrinter name or wildcard\n"
1503 " servername\tName of the print server\n");
1504 return 0;
1507 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1508 return -1;
1511 if (argc > 0) {
1512 printername = argv[0];
1513 } else {
1514 printername = "*";
1517 if (argc > 1) {
1518 servername = argv[1];
1519 } else {
1520 servername = global_myname();
1523 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1525 if (!ADS_ERR_OK(rc)) {
1526 d_fprintf(stderr, "Server '%s' not found: %s\n",
1527 servername, ads_errstr(rc));
1528 ads_msgfree(ads, res);
1529 ads_destroy(&ads);
1530 return -1;
1533 if (ads_count_replies(ads, res) == 0) {
1534 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1535 ads_msgfree(ads, res);
1536 ads_destroy(&ads);
1537 return -1;
1540 ads_dump(ads, res);
1541 ads_msgfree(ads, res);
1542 ads_destroy(&ads);
1544 return 0;
1547 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1549 ADS_STRUCT *ads;
1550 ADS_STATUS rc;
1551 const char *servername, *printername;
1552 struct cli_state *cli;
1553 struct rpc_pipe_client *pipe_hnd;
1554 struct sockaddr_storage server_ss;
1555 NTSTATUS nt_status;
1556 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1557 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1558 char *prt_dn, *srv_dn, **srv_cn;
1559 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1560 LDAPMessage *res = NULL;
1562 if (argc < 1 || c->display_usage) {
1563 d_printf("Usage:\n"
1564 "net ads printer publish <printername> [servername]\n"
1565 " Publish printer in AD\n"
1566 " printername\tName of the printer\n"
1567 " servername\tName of the print server\n");
1568 talloc_destroy(mem_ctx);
1569 return -1;
1572 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1573 talloc_destroy(mem_ctx);
1574 return -1;
1577 printername = argv[0];
1579 if (argc == 2) {
1580 servername = argv[1];
1581 } else {
1582 servername = global_myname();
1585 /* Get printer data from SPOOLSS */
1587 resolve_name(servername, &server_ss, 0x20);
1589 nt_status = cli_full_connection(&cli, global_myname(), servername,
1590 &server_ss, 0,
1591 "IPC$", "IPC",
1592 c->opt_user_name, c->opt_workgroup,
1593 c->opt_password ? c->opt_password : "",
1594 CLI_FULL_CONNECTION_USE_KERBEROS,
1595 Undefined, NULL);
1597 if (NT_STATUS_IS_ERR(nt_status)) {
1598 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1599 "for %s\n", servername, printername);
1600 ads_destroy(&ads);
1601 talloc_destroy(mem_ctx);
1602 return -1;
1605 /* Publish on AD server */
1607 ads_find_machine_acct(ads, &res, servername);
1609 if (ads_count_replies(ads, res) == 0) {
1610 d_fprintf(stderr, "Could not find machine account for server %s\n",
1611 servername);
1612 ads_destroy(&ads);
1613 talloc_destroy(mem_ctx);
1614 return -1;
1617 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1618 srv_cn = ldap_explode_dn(srv_dn, 1);
1620 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1621 printername_escaped = escape_rdn_val_string_alloc(printername);
1622 if (!srv_cn_escaped || !printername_escaped) {
1623 SAFE_FREE(srv_cn_escaped);
1624 SAFE_FREE(printername_escaped);
1625 d_fprintf(stderr, "Internal error, out of memory!");
1626 ads_destroy(&ads);
1627 talloc_destroy(mem_ctx);
1628 return -1;
1631 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1633 SAFE_FREE(srv_cn_escaped);
1634 SAFE_FREE(printername_escaped);
1636 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1637 if (!pipe_hnd) {
1638 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1639 servername);
1640 SAFE_FREE(prt_dn);
1641 ads_destroy(&ads);
1642 talloc_destroy(mem_ctx);
1643 return -1;
1646 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1647 printername))) {
1648 SAFE_FREE(prt_dn);
1649 ads_destroy(&ads);
1650 talloc_destroy(mem_ctx);
1651 return -1;
1654 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1655 if (!ADS_ERR_OK(rc)) {
1656 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1657 SAFE_FREE(prt_dn);
1658 ads_destroy(&ads);
1659 talloc_destroy(mem_ctx);
1660 return -1;
1663 d_printf("published printer\n");
1664 SAFE_FREE(prt_dn);
1665 ads_destroy(&ads);
1666 talloc_destroy(mem_ctx);
1668 return 0;
1671 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1673 ADS_STRUCT *ads;
1674 ADS_STATUS rc;
1675 const char *servername;
1676 char *prt_dn;
1677 LDAPMessage *res = NULL;
1679 if (argc < 1 || c->display_usage) {
1680 d_printf("Usage:\n"
1681 "net ads printer remove <printername> [servername]\n"
1682 " Remove a printer from the AD\n"
1683 " printername\tName of the printer\n"
1684 " servername\tName of the print server\n");
1685 return -1;
1688 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1689 return -1;
1692 if (argc > 1) {
1693 servername = argv[1];
1694 } else {
1695 servername = global_myname();
1698 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1700 if (!ADS_ERR_OK(rc)) {
1701 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1702 ads_msgfree(ads, res);
1703 ads_destroy(&ads);
1704 return -1;
1707 if (ads_count_replies(ads, res) == 0) {
1708 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1709 ads_msgfree(ads, res);
1710 ads_destroy(&ads);
1711 return -1;
1714 prt_dn = ads_get_dn(ads, res);
1715 ads_msgfree(ads, res);
1716 rc = ads_del_dn(ads, prt_dn);
1717 ads_memfree(ads, prt_dn);
1719 if (!ADS_ERR_OK(rc)) {
1720 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1721 ads_destroy(&ads);
1722 return -1;
1725 ads_destroy(&ads);
1726 return 0;
1729 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1731 struct functable func[] = {
1733 "search",
1734 net_ads_printer_search,
1735 NET_TRANSPORT_ADS,
1736 "Search for a printer",
1737 "net ads printer search\n"
1738 " Search for a printer"
1741 "info",
1742 net_ads_printer_info,
1743 NET_TRANSPORT_ADS,
1744 "Display printer information",
1745 "net ads printer info\n"
1746 " Display printer information"
1749 "publish",
1750 net_ads_printer_publish,
1751 NET_TRANSPORT_ADS,
1752 "Publish a printer",
1753 "net ads printer publish\n"
1754 " Publish a printer"
1757 "remove",
1758 net_ads_printer_remove,
1759 NET_TRANSPORT_ADS,
1760 "Delete a printer",
1761 "net ads printer remove\n"
1762 " Delete a printer"
1764 {NULL, NULL, 0, NULL, NULL}
1767 return net_run_function(c, argc, argv, "net ads printer", func);
1771 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1773 ADS_STRUCT *ads;
1774 const char *auth_principal = c->opt_user_name;
1775 const char *auth_password = c->opt_password;
1776 char *realm = NULL;
1777 char *new_password = NULL;
1778 char *chr, *prompt;
1779 const char *user;
1780 ADS_STATUS ret;
1782 if (c->display_usage) {
1783 d_printf("Usage:\n"
1784 "net ads password <username>\n"
1785 " Change password for user\n"
1786 " username\tName of user to change password for\n");
1787 return 0;
1790 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1791 d_fprintf(stderr, "You must supply an administrator username/password\n");
1792 return -1;
1795 if (argc < 1) {
1796 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1797 return -1;
1800 user = argv[0];
1801 if (!strchr_m(user, '@')) {
1802 asprintf(&chr, "%s@%s", argv[0], lp_realm());
1803 user = chr;
1806 use_in_memory_ccache();
1807 chr = strchr_m(auth_principal, '@');
1808 if (chr) {
1809 realm = ++chr;
1810 } else {
1811 realm = lp_realm();
1814 /* use the realm so we can eventually change passwords for users
1815 in realms other than default */
1816 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1817 return -1;
1820 /* we don't actually need a full connect, but it's the easy way to
1821 fill in the KDC's addresss */
1822 ads_connect(ads);
1824 if (!ads->config.realm) {
1825 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1826 return -1;
1829 if (argv[1]) {
1830 new_password = (char *)argv[1];
1831 } else {
1832 asprintf(&prompt, "Enter new password for %s:", user);
1833 new_password = getpass(prompt);
1834 free(prompt);
1837 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1838 auth_password, user, new_password, ads->auth.time_offset);
1839 if (!ADS_ERR_OK(ret)) {
1840 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1841 ads_destroy(&ads);
1842 return -1;
1845 d_printf("Password change for %s completed.\n", user);
1846 ads_destroy(&ads);
1848 return 0;
1851 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1853 ADS_STRUCT *ads;
1854 char *host_principal;
1855 fstring my_name;
1856 ADS_STATUS ret;
1858 if (c->display_usage) {
1859 d_printf("Usage:\n"
1860 "net ads changetrustpw\n"
1861 " Change the machine account's trust password\n");
1862 return 0;
1865 if (!secrets_init()) {
1866 DEBUG(1,("Failed to initialise secrets database\n"));
1867 return -1;
1870 net_use_krb_machine_account(c);
1872 use_in_memory_ccache();
1874 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1875 return -1;
1878 fstrcpy(my_name, global_myname());
1879 strlower_m(my_name);
1880 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1881 d_printf("Changing password for principal: %s\n", host_principal);
1883 ret = ads_change_trust_account_password(ads, host_principal);
1885 if (!ADS_ERR_OK(ret)) {
1886 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1887 ads_destroy(&ads);
1888 SAFE_FREE(host_principal);
1889 return -1;
1892 d_printf("Password change for principal %s succeeded.\n", host_principal);
1894 if (lp_use_kerberos_keytab()) {
1895 d_printf("Attempting to update system keytab with new password.\n");
1896 if (ads_keytab_create_default(ads)) {
1897 d_printf("Failed to update system keytab.\n");
1901 ads_destroy(&ads);
1902 SAFE_FREE(host_principal);
1904 return 0;
1908 help for net ads search
1910 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
1912 d_printf(
1913 "\nnet ads search <expression> <attributes...>\n"
1914 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1915 "The expression is a standard LDAP search expression, and the\n"
1916 "attributes are a list of LDAP fields to show in the results.\n\n"
1917 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1919 net_common_flags_usage(c, argc, argv);
1920 return -1;
1925 general ADS search function. Useful in diagnosing problems in ADS
1927 static int net_ads_search(struct net_context *c, int argc, const char **argv)
1929 ADS_STRUCT *ads;
1930 ADS_STATUS rc;
1931 const char *ldap_exp;
1932 const char **attrs;
1933 LDAPMessage *res = NULL;
1935 if (argc < 1 || c->display_usage) {
1936 return net_ads_search_usage(c, argc, argv);
1939 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1940 return -1;
1943 ldap_exp = argv[0];
1944 attrs = (argv + 1);
1946 rc = ads_do_search_all(ads, ads->config.bind_path,
1947 LDAP_SCOPE_SUBTREE,
1948 ldap_exp, attrs, &res);
1949 if (!ADS_ERR_OK(rc)) {
1950 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1951 ads_destroy(&ads);
1952 return -1;
1955 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1957 /* dump the results */
1958 ads_dump(ads, res);
1960 ads_msgfree(ads, res);
1961 ads_destroy(&ads);
1963 return 0;
1968 help for net ads search
1970 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
1972 d_printf(
1973 "\nnet ads dn <dn> <attributes...>\n"
1974 "\nperform a raw LDAP search on a ADS server and dump the results\n"
1975 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
1976 "to show in the results\n\n"
1977 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1978 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1980 net_common_flags_usage(c, argc, argv);
1981 return -1;
1986 general ADS search function. Useful in diagnosing problems in ADS
1988 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
1990 ADS_STRUCT *ads;
1991 ADS_STATUS rc;
1992 const char *dn;
1993 const char **attrs;
1994 LDAPMessage *res = NULL;
1996 if (argc < 1 || c->display_usage) {
1997 return net_ads_dn_usage(c, argc, argv);
2000 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2001 return -1;
2004 dn = argv[0];
2005 attrs = (argv + 1);
2007 rc = ads_do_search_all(ads, dn,
2008 LDAP_SCOPE_BASE,
2009 "(objectclass=*)", attrs, &res);
2010 if (!ADS_ERR_OK(rc)) {
2011 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2012 ads_destroy(&ads);
2013 return -1;
2016 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2018 /* dump the results */
2019 ads_dump(ads, res);
2021 ads_msgfree(ads, res);
2022 ads_destroy(&ads);
2024 return 0;
2028 help for net ads sid search
2030 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2032 d_printf(
2033 "\nnet ads sid <sid> <attributes...>\n"
2034 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2035 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2036 "to show in the results\n\n"
2037 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2039 net_common_flags_usage(c, argc, argv);
2040 return -1;
2045 general ADS search function. Useful in diagnosing problems in ADS
2047 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2049 ADS_STRUCT *ads;
2050 ADS_STATUS rc;
2051 const char *sid_string;
2052 const char **attrs;
2053 LDAPMessage *res = NULL;
2054 DOM_SID sid;
2056 if (argc < 1 || c->display_usage) {
2057 return net_ads_sid_usage(c, argc, argv);
2060 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2061 return -1;
2064 sid_string = argv[0];
2065 attrs = (argv + 1);
2067 if (!string_to_sid(&sid, sid_string)) {
2068 d_fprintf(stderr, "could not convert sid\n");
2069 ads_destroy(&ads);
2070 return -1;
2073 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2074 if (!ADS_ERR_OK(rc)) {
2075 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2076 ads_destroy(&ads);
2077 return -1;
2080 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2082 /* dump the results */
2083 ads_dump(ads, res);
2085 ads_msgfree(ads, res);
2086 ads_destroy(&ads);
2088 return 0;
2091 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2093 int ret;
2094 ADS_STRUCT *ads;
2096 if (c->display_usage) {
2097 d_printf("Usage:\n"
2098 "net ads keytab flush\n"
2099 " Delete the whole keytab\n");
2100 return 0;
2103 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2104 return -1;
2106 ret = ads_keytab_flush(ads);
2107 ads_destroy(&ads);
2108 return ret;
2111 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2113 int i;
2114 int ret = 0;
2115 ADS_STRUCT *ads;
2117 if (c->display_usage) {
2118 d_printf("Usage:\n"
2119 "net ads keytab add <principal> [principal ...]\n"
2120 " Add principals to local keytab\n"
2121 " principal\tKerberos principal to add to "
2122 "keytab\n");
2123 return 0;
2126 d_printf("Processing principals to add...\n");
2127 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2128 return -1;
2130 for (i = 0; i < argc; i++) {
2131 ret |= ads_keytab_add_entry(ads, argv[i]);
2133 ads_destroy(&ads);
2134 return ret;
2137 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2139 ADS_STRUCT *ads;
2140 int ret;
2142 if (c->display_usage) {
2143 d_printf("Usage:\n"
2144 "net ads keytab create\n"
2145 " Create new default keytab\n");
2146 return 0;
2149 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2150 return -1;
2152 ret = ads_keytab_create_default(ads);
2153 ads_destroy(&ads);
2154 return ret;
2157 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2159 const char *keytab = NULL;
2161 if (c->display_usage) {
2162 d_printf("Usage:\n"
2163 "net ads keytab list [keytab]\n"
2164 " List a local keytab\n"
2165 " keytab\tKeytab to list\n");
2166 return 0;
2169 if (argc >= 1) {
2170 keytab = argv[0];
2173 return ads_keytab_list(keytab);
2177 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2179 struct functable func[] = {
2181 "add",
2182 net_ads_keytab_add,
2183 NET_TRANSPORT_ADS,
2184 "Add a service principal",
2185 "net ads keytab add\n"
2186 " Add a service principal"
2189 "create",
2190 net_ads_keytab_create,
2191 NET_TRANSPORT_ADS,
2192 "Create a fresh keytab",
2193 "net ads keytab create\n"
2194 " Create a fresh keytab"
2197 "flush",
2198 net_ads_keytab_flush,
2199 NET_TRANSPORT_ADS,
2200 "Remove all keytab entries",
2201 "net ads keytab flush\n"
2202 " Remove all keytab entries"
2205 "list",
2206 net_ads_keytab_list,
2207 NET_TRANSPORT_ADS,
2208 "List a keytab",
2209 "net ads keytab list\n"
2210 " List a keytab"
2212 {NULL, NULL, 0, NULL, NULL}
2215 if (!lp_use_kerberos_keytab()) {
2216 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2217 use keytab functions.\n");
2220 return net_run_function(c, argc, argv, "net ads keytab", func);
2223 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2225 int ret = -1;
2227 if (c->display_usage) {
2228 d_printf("Usage:\n"
2229 "net ads kerberos renew\n"
2230 " Renew TGT from existing credential cache\n");
2231 return 0;
2234 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2235 if (ret) {
2236 d_printf("failed to renew kerberos ticket: %s\n",
2237 error_message(ret));
2239 return ret;
2242 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2244 struct PAC_DATA *pac = NULL;
2245 struct PAC_LOGON_INFO *info = NULL;
2246 TALLOC_CTX *mem_ctx = NULL;
2247 NTSTATUS status;
2248 int ret = -1;
2250 if (c->display_usage) {
2251 d_printf("Usage:\n"
2252 "net ads kerberos pac\n"
2253 " Dump the Kerberos PAC\n");
2254 return 0;
2257 mem_ctx = talloc_init("net_ads_kerberos_pac");
2258 if (!mem_ctx) {
2259 goto out;
2262 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2264 status = kerberos_return_pac(mem_ctx,
2265 c->opt_user_name,
2266 c->opt_password,
2268 NULL,
2269 NULL,
2270 NULL,
2271 true,
2272 true,
2273 2592000, /* one month */
2274 &pac);
2275 if (!NT_STATUS_IS_OK(status)) {
2276 d_printf("failed to query kerberos PAC: %s\n",
2277 nt_errstr(status));
2278 goto out;
2281 info = get_logon_info_from_pac(pac);
2282 if (info) {
2283 const char *s;
2284 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2285 d_printf("The Pac: %s\n", s);
2288 ret = 0;
2289 out:
2290 TALLOC_FREE(mem_ctx);
2291 return ret;
2294 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2296 TALLOC_CTX *mem_ctx = NULL;
2297 int ret = -1;
2298 NTSTATUS status;
2300 if (c->display_usage) {
2301 d_printf("Usage:\n"
2302 "net ads kerberos kinit\n"
2303 " Get Ticket Granting Ticket (TGT) for the user\n");
2304 return 0;
2307 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2308 if (!mem_ctx) {
2309 goto out;
2312 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2314 ret = kerberos_kinit_password_ext(c->opt_user_name,
2315 c->opt_password,
2317 NULL,
2318 NULL,
2319 NULL,
2320 true,
2321 true,
2322 2592000, /* one month */
2323 &status);
2324 if (ret) {
2325 d_printf("failed to kinit password: %s\n",
2326 nt_errstr(status));
2328 out:
2329 return ret;
2332 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2334 struct functable func[] = {
2336 "kinit",
2337 net_ads_kerberos_kinit,
2338 NET_TRANSPORT_ADS,
2339 "Retrieve Ticket Granting Ticket (TGT)",
2340 "net ads kerberos kinit\n"
2341 " Receive Ticket Granting Ticket (TGT)"
2344 "renew",
2345 net_ads_kerberos_renew,
2346 NET_TRANSPORT_ADS,
2347 "Renew Ticket Granting Ticket from credential cache"
2348 "net ads kerberos renew\n"
2349 " Renew Ticket Granting Ticket from credential cache"
2352 "pac",
2353 net_ads_kerberos_pac,
2354 NET_TRANSPORT_ADS,
2355 "Dump Kerberos PAC",
2356 "net ads kerberos pac\n"
2357 " Dump Kerberos PAC"
2359 {NULL, NULL, 0, NULL, NULL}
2362 return net_run_function(c, argc, argv, "net ads kerberos", func);
2365 int net_ads(struct net_context *c, int argc, const char **argv)
2367 struct functable func[] = {
2369 "info",
2370 net_ads_info,
2371 NET_TRANSPORT_ADS,
2372 "Display details on remote ADS server",
2373 "net ads info\n"
2374 " Display details on remote ADS server"
2377 "join",
2378 net_ads_join,
2379 NET_TRANSPORT_ADS,
2380 "Join the local machine to ADS realm",
2381 "net ads join\n"
2382 " Join the local machine to ADS realm"
2385 "testjoin",
2386 net_ads_testjoin,
2387 NET_TRANSPORT_ADS,
2388 "Validate machine account",
2389 "net ads testjoin\n"
2390 " Validate machine account"
2393 "leave",
2394 net_ads_leave,
2395 NET_TRANSPORT_ADS,
2396 "Remove the local machine from ADS",
2397 "net ads leave\n"
2398 " Remove the local machine from ADS"
2401 "status",
2402 net_ads_status,
2403 NET_TRANSPORT_ADS,
2404 "Display machine account details",
2405 "net ads status\n"
2406 " Display machine account details"
2409 "user",
2410 net_ads_user,
2411 NET_TRANSPORT_ADS,
2412 "List/modify users",
2413 "net ads user\n"
2414 " List/modify users"
2417 "group",
2418 net_ads_group,
2419 NET_TRANSPORT_ADS,
2420 "List/modify groups",
2421 "net ads group\n"
2422 " List/modify groups"
2425 "dns",
2426 net_ads_dns,
2427 NET_TRANSPORT_ADS,
2428 "Issue dynamic DNS update",
2429 "net ads dns\n"
2430 " Issue dynamic DNS update"
2433 "password",
2434 net_ads_password,
2435 NET_TRANSPORT_ADS,
2436 "Change user passwords",
2437 "net ads password\n"
2438 " Change user passwords"
2441 "changetrustpw",
2442 net_ads_changetrustpw,
2443 NET_TRANSPORT_ADS,
2444 "Change trust account password",
2445 "net ads changetrustpw\n"
2446 " Change trust account password"
2449 "printer",
2450 net_ads_printer,
2451 NET_TRANSPORT_ADS,
2452 "List/modify printer entries",
2453 "net ads printer\n"
2454 " List/modify printer entries"
2457 "search",
2458 net_ads_search,
2459 NET_TRANSPORT_ADS,
2460 "Issue LDAP search using filter",
2461 "net ads search\n"
2462 " Issue LDAP search using filter"
2465 "dn",
2466 net_ads_dn,
2467 NET_TRANSPORT_ADS,
2468 "Issue LDAP search by DN",
2469 "net ads dn\n"
2470 " Issue LDAP search by DN"
2473 "sid",
2474 net_ads_sid,
2475 NET_TRANSPORT_ADS,
2476 "Issue LDAP search by SID",
2477 "net ads sid\n"
2478 " Issue LDAP search by SID"
2481 "workgroup",
2482 net_ads_workgroup,
2483 NET_TRANSPORT_ADS,
2484 "Display workgroup name",
2485 "net ads workgroup\n"
2486 " Display the workgroup name"
2489 "lookup",
2490 net_ads_lookup,
2491 NET_TRANSPORT_ADS,
2492 "Perfom CLDAP query on DC",
2493 "net ads lookup\n"
2494 " Find the ADS DC using CLDAP lookups"
2497 "keytab",
2498 net_ads_keytab,
2499 NET_TRANSPORT_ADS,
2500 "Manage local keytab file",
2501 "net ads keytab\n"
2502 " Manage local keytab file"
2505 "gpo",
2506 net_ads_gpo,
2507 NET_TRANSPORT_ADS,
2508 "Manage group policy objects",
2509 "net ads gpo\n"
2510 " Manage group policy objects"
2513 "kerberos",
2514 net_ads_kerberos,
2515 NET_TRANSPORT_ADS,
2516 "Manage kerberos keytab",
2517 "net ads kerberos\n"
2518 " Manage kerberos keytab"
2520 {NULL, NULL, 0, NULL, NULL}
2523 return net_run_function(c, argc, argv, "net ads", func);
2526 #else
2528 static int net_ads_noads(void)
2530 d_fprintf(stderr, "ADS support not compiled in\n");
2531 return -1;
2534 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2536 return net_ads_noads();
2539 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2541 return net_ads_noads();
2544 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2546 return net_ads_noads();
2549 int net_ads_join(struct net_context *c, int argc, const char **argv)
2551 return net_ads_noads();
2554 int net_ads_user(struct net_context *c, int argc, const char **argv)
2556 return net_ads_noads();
2559 int net_ads_group(struct net_context *c, int argc, const char **argv)
2561 return net_ads_noads();
2564 /* this one shouldn't display a message */
2565 int net_ads_check(struct net_context *c)
2567 return -1;
2570 int net_ads_check_our_domain(struct net_context *c)
2572 return -1;
2575 int net_ads(struct net_context *c, int argc, const char **argv)
2577 return net_ads_noads();
2580 #endif /* WITH_ADS */