s3-nbt: remove double nbt netlogon opcodes.
[Samba.git] / source / utils / net_ads.c
blob627374cb96bb82162a7f31f01849479ad8fb52f3
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 NETLOGON_SAM_LOGON_RESPONSE_EX 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.command) {
59 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
60 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
61 break;
62 case LOGON_SAM_LOGON_RESPONSE_EX:
63 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
64 break;
65 default:
66 d_printf("0x%x\n", reply.command);
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 NETLOGON_SAM_LOGON_RESPONSE_EX 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 if (!c->opt_kerberos) {
883 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.use_kerberos = c->opt_kerberos;
894 r->in.dc_name = c->opt_host;
895 r->in.domain_name = lp_realm();
896 r->in.admin_account = c->opt_user_name;
897 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
898 r->in.modify_config = lp_config_backend_is_registry();
899 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
900 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
902 werr = libnet_Unjoin(ctx, r);
903 if (!W_ERROR_IS_OK(werr)) {
904 d_printf("Failed to leave domain: %s\n",
905 r->out.error_string ? r->out.error_string :
906 get_friendly_werror_msg(werr));
907 goto done;
910 if (W_ERROR_IS_OK(werr)) {
911 d_printf("Deleted account for '%s' in realm '%s'\n",
912 r->in.machine_name, r->out.dns_domain_name);
913 goto done;
916 /* We couldn't delete it - see if the disable succeeded. */
917 if (r->out.disabled_machine_account) {
918 d_printf("Disabled account for '%s' in realm '%s'\n",
919 r->in.machine_name, r->out.dns_domain_name);
920 werr = WERR_OK;
921 goto done;
924 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
925 r->in.machine_name, r->out.dns_domain_name);
927 done:
928 TALLOC_FREE(r);
929 TALLOC_FREE(ctx);
931 if (W_ERROR_IS_OK(werr)) {
932 return 0;
935 return -1;
938 static NTSTATUS net_ads_join_ok(struct net_context *c)
940 ADS_STRUCT *ads = NULL;
941 ADS_STATUS status;
943 if (!secrets_init()) {
944 DEBUG(1,("Failed to initialise secrets database\n"));
945 return NT_STATUS_ACCESS_DENIED;
948 net_use_krb_machine_account(c);
950 status = ads_startup(c, true, &ads);
951 if (!ADS_ERR_OK(status)) {
952 return ads_ntstatus(status);
955 ads_destroy(&ads);
956 return NT_STATUS_OK;
960 check that an existing join is OK
962 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
964 NTSTATUS status;
965 use_in_memory_ccache();
967 if (c->display_usage) {
968 d_printf("Usage:\n"
969 "net ads testjoin\n"
970 " Test if the existing join is ok\n");
971 return 0;
974 /* Display success or failure */
975 status = net_ads_join_ok(c);
976 if (!NT_STATUS_IS_OK(status)) {
977 fprintf(stderr,"Join to domain is not valid: %s\n",
978 get_friendly_nt_error_msg(status));
979 return -1;
982 printf("Join is OK\n");
983 return 0;
986 /*******************************************************************
987 Simple configu checks before beginning the join
988 ********************************************************************/
990 static WERROR check_ads_config( void )
992 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
993 d_printf("Host is not configured as a member server.\n");
994 return WERR_INVALID_DOMAIN_ROLE;
997 if (strlen(global_myname()) > 15) {
998 d_printf("Our netbios name can be at most 15 chars long, "
999 "\"%s\" is %u chars long\n", global_myname(),
1000 (unsigned int)strlen(global_myname()));
1001 return WERR_INVALID_COMPUTER_NAME;
1004 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1005 d_fprintf(stderr, "realm must be set in in %s for ADS "
1006 "join to succeed.\n", get_dyn_CONFIGFILE());
1007 return WERR_INVALID_PARAM;
1010 return WERR_OK;
1013 /*******************************************************************
1014 Send a DNS update request
1015 *******************************************************************/
1017 #if defined(WITH_DNS_UPDATES)
1018 #include "dns.h"
1019 DNS_ERROR DoDNSUpdate(char *pszServerName,
1020 const char *pszDomainName, const char *pszHostName,
1021 const struct sockaddr_storage *sslist,
1022 size_t num_addrs );
1024 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1025 const char *machine_name,
1026 const struct sockaddr_storage *addrs,
1027 int num_addrs)
1029 struct dns_rr_ns *nameservers = NULL;
1030 int ns_count = 0;
1031 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1032 DNS_ERROR dns_err;
1033 fstring dns_server;
1034 const char *dnsdomain = NULL;
1035 char *root_domain = NULL;
1037 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1038 d_printf("No DNS domain configured for %s. "
1039 "Unable to perform DNS Update.\n", machine_name);
1040 status = NT_STATUS_INVALID_PARAMETER;
1041 goto done;
1043 dnsdomain++;
1045 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1046 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1047 /* Child domains often do not have NS records. Look
1048 for the NS record for the forest root domain
1049 (rootDomainNamingContext in therootDSE) */
1051 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1052 LDAPMessage *msg = NULL;
1053 char *root_dn;
1054 ADS_STATUS ads_status;
1056 if ( !ads->ldap.ld ) {
1057 ads_status = ads_connect( ads );
1058 if ( !ADS_ERR_OK(ads_status) ) {
1059 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1060 goto done;
1064 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1065 "(objectclass=*)", rootname_attrs, &msg);
1066 if (!ADS_ERR_OK(ads_status)) {
1067 goto done;
1070 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1071 if ( !root_dn ) {
1072 ads_msgfree( ads, msg );
1073 goto done;
1076 root_domain = ads_build_domain( root_dn );
1078 /* cleanup */
1079 ads_msgfree( ads, msg );
1081 /* try again for NS servers */
1083 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1085 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1086 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1087 "realm\n", ads->config.realm));
1088 goto done;
1091 dnsdomain = root_domain;
1095 /* Now perform the dns update - we'll try non-secure and if we fail,
1096 we'll follow it up with a secure update */
1098 fstrcpy( dns_server, nameservers[0].hostname );
1100 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1101 if (!ERR_DNS_IS_OK(dns_err)) {
1102 status = NT_STATUS_UNSUCCESSFUL;
1105 done:
1107 SAFE_FREE( root_domain );
1109 return status;
1112 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1114 int num_addrs;
1115 struct sockaddr_storage *iplist = NULL;
1116 fstring machine_name;
1117 NTSTATUS status;
1119 name_to_fqdn( machine_name, global_myname() );
1120 strlower_m( machine_name );
1122 /* Get our ip address (not the 127.0.0.x address but a real ip
1123 * address) */
1125 num_addrs = get_my_ip_address( &iplist );
1126 if ( num_addrs <= 0 ) {
1127 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1128 "addresses!\n"));
1129 return NT_STATUS_INVALID_PARAMETER;
1132 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1133 iplist, num_addrs);
1134 SAFE_FREE( iplist );
1135 return status;
1137 #endif
1140 /*******************************************************************
1141 ********************************************************************/
1143 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1145 d_printf("net ads join [options]\n");
1146 d_printf("Valid options:\n");
1147 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1148 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1149 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1150 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1151 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1152 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1153 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1154 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1155 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1156 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1157 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1158 d_printf(" the two other attributes.\n");
1160 return -1;
1163 /*******************************************************************
1164 ********************************************************************/
1166 int net_ads_join(struct net_context *c, int argc, const char **argv)
1168 TALLOC_CTX *ctx = NULL;
1169 struct libnet_JoinCtx *r = NULL;
1170 const char *domain = lp_realm();
1171 WERROR werr = WERR_SETUP_NOT_JOINED;
1172 bool createupn = false;
1173 const char *machineupn = NULL;
1174 const char *create_in_ou = NULL;
1175 int i;
1176 const char *os_name = NULL;
1177 const char *os_version = NULL;
1178 bool modify_config = lp_config_backend_is_registry();
1180 if (c->display_usage)
1181 return net_ads_join_usage(c, argc, argv);
1183 if (!modify_config) {
1185 werr = check_ads_config();
1186 if (!W_ERROR_IS_OK(werr)) {
1187 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1188 goto fail;
1192 if (!(ctx = talloc_init("net_ads_join"))) {
1193 d_fprintf(stderr, "Could not initialise talloc context.\n");
1194 werr = WERR_NOMEM;
1195 goto fail;
1198 if (!c->opt_kerberos) {
1199 use_in_memory_ccache();
1202 werr = libnet_init_JoinCtx(ctx, &r);
1203 if (!W_ERROR_IS_OK(werr)) {
1204 goto fail;
1207 /* process additional command line args */
1209 for ( i=0; i<argc; i++ ) {
1210 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1211 createupn = true;
1212 machineupn = get_string_param(argv[i]);
1214 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1215 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1216 d_fprintf(stderr, "Please supply a valid OU path.\n");
1217 werr = WERR_INVALID_PARAM;
1218 goto fail;
1221 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1222 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1223 d_fprintf(stderr, "Please supply a operating system name.\n");
1224 werr = WERR_INVALID_PARAM;
1225 goto fail;
1228 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1229 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1230 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1231 werr = WERR_INVALID_PARAM;
1232 goto fail;
1235 else {
1236 domain = argv[i];
1240 if (!*domain) {
1241 d_fprintf(stderr, "Please supply a valid domain name\n");
1242 werr = WERR_INVALID_PARAM;
1243 goto fail;
1246 /* Do the domain join here */
1248 r->in.domain_name = domain;
1249 r->in.create_upn = createupn;
1250 r->in.upn = machineupn;
1251 r->in.account_ou = create_in_ou;
1252 r->in.os_name = os_name;
1253 r->in.os_version = os_version;
1254 r->in.dc_name = c->opt_host;
1255 r->in.admin_account = c->opt_user_name;
1256 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1257 r->in.debug = true;
1258 r->in.use_kerberos = c->opt_kerberos;
1259 r->in.modify_config = modify_config;
1260 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1261 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1262 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1264 werr = libnet_Join(ctx, r);
1265 if (!W_ERROR_IS_OK(werr)) {
1266 goto fail;
1269 /* Check the short name of the domain */
1271 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1272 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1273 d_printf("domain name obtained from the server.\n");
1274 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1275 d_printf("You should set \"workgroup = %s\" in %s.\n",
1276 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1279 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1281 if (r->out.dns_domain_name) {
1282 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1283 r->out.dns_domain_name);
1284 } else {
1285 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1286 r->out.netbios_domain_name);
1289 #if defined(WITH_DNS_UPDATES)
1290 if (r->out.domain_is_ad) {
1291 /* We enter this block with user creds */
1292 ADS_STRUCT *ads_dns = NULL;
1294 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1295 /* kinit with the machine password */
1297 use_in_memory_ccache();
1298 asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1299 ads_dns->auth.password = secrets_fetch_machine_password(
1300 r->out.netbios_domain_name, NULL, NULL );
1301 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1302 strupper_m(ads_dns->auth.realm );
1303 ads_kinit_password( ads_dns );
1306 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1307 d_fprintf( stderr, "DNS update failed!\n" );
1310 /* exit from this block using machine creds */
1311 ads_destroy(&ads_dns);
1313 #endif
1314 TALLOC_FREE(r);
1315 TALLOC_FREE( ctx );
1317 return 0;
1319 fail:
1320 /* issue an overall failure message at the end. */
1321 d_printf("Failed to join domain: %s\n",
1322 r && r->out.error_string ? r->out.error_string :
1323 get_friendly_werror_msg(werr));
1324 TALLOC_FREE( ctx );
1326 return -1;
1329 /*******************************************************************
1330 ********************************************************************/
1332 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1334 #if defined(WITH_DNS_UPDATES)
1335 ADS_STRUCT *ads;
1336 ADS_STATUS status;
1337 TALLOC_CTX *ctx;
1339 #ifdef DEVELOPER
1340 talloc_enable_leak_report();
1341 #endif
1343 if (argc > 0 || c->display_usage) {
1344 d_printf("Usage:\n"
1345 "net ads dns register\n"
1346 " Register hostname with DNS\n");
1347 return -1;
1350 if (!(ctx = talloc_init("net_ads_dns"))) {
1351 d_fprintf(stderr, "Could not initialise talloc context\n");
1352 return -1;
1355 status = ads_startup(c, true, &ads);
1356 if ( !ADS_ERR_OK(status) ) {
1357 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1358 TALLOC_FREE(ctx);
1359 return -1;
1362 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1363 d_fprintf( stderr, "DNS update failed!\n" );
1364 ads_destroy( &ads );
1365 TALLOC_FREE( ctx );
1366 return -1;
1369 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1371 ads_destroy(&ads);
1372 TALLOC_FREE( ctx );
1374 return 0;
1375 #else
1376 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1377 return -1;
1378 #endif
1381 #if defined(WITH_DNS_UPDATES)
1382 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1383 #endif
1385 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1387 #if defined(WITH_DNS_UPDATES)
1388 DNS_ERROR err;
1390 #ifdef DEVELOPER
1391 talloc_enable_leak_report();
1392 #endif
1394 if (argc != 2 || c->display_usage) {
1395 d_printf("Usage:\n"
1396 "net ads dns gethostbyname <server> <name>\n"
1397 " Look up hostname from the AD\n"
1398 " server\tName server to use\n"
1399 " name\tName to look up\n");
1400 return -1;
1403 err = do_gethostbyname(argv[0], argv[1]);
1405 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1406 #endif
1407 return 0;
1410 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1412 struct functable func[] = {
1414 "register",
1415 net_ads_dns_register,
1416 NET_TRANSPORT_ADS,
1417 "Add host dns entry to AD",
1418 "net ads dns register\n"
1419 " Add host dns entry to AD"
1422 "gethostbyname",
1423 net_ads_dns_gethostbyname,
1424 NET_TRANSPORT_ADS,
1425 "Look up host",
1426 "net ads dns gethostbyname\n"
1427 " Look up host"
1429 {NULL, NULL, 0, NULL, NULL}
1432 return net_run_function(c, argc, argv, "net ads dns", func);
1435 /*******************************************************************
1436 ********************************************************************/
1438 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1440 d_printf(
1441 "\nnet ads printer search <printer>"
1442 "\n\tsearch for a printer in the directory\n"
1443 "\nnet ads printer info <printer> <server>"
1444 "\n\tlookup info in directory for printer on server"
1445 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1446 "\nnet ads printer publish <printername>"
1447 "\n\tpublish printer in directory"
1448 "\n\t(note: printer name is required)\n"
1449 "\nnet ads printer remove <printername>"
1450 "\n\tremove printer from directory"
1451 "\n\t(note: printer name is required)\n");
1452 return -1;
1455 /*******************************************************************
1456 ********************************************************************/
1458 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1460 ADS_STRUCT *ads;
1461 ADS_STATUS rc;
1462 LDAPMessage *res = NULL;
1464 if (c->display_usage) {
1465 d_printf("Usage:\n"
1466 "net ads printer search\n"
1467 " List printers in the AD\n");
1468 return 0;
1471 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1472 return -1;
1475 rc = ads_find_printers(ads, &res);
1477 if (!ADS_ERR_OK(rc)) {
1478 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1479 ads_msgfree(ads, res);
1480 ads_destroy(&ads);
1481 return -1;
1484 if (ads_count_replies(ads, res) == 0) {
1485 d_fprintf(stderr, "No results found\n");
1486 ads_msgfree(ads, res);
1487 ads_destroy(&ads);
1488 return -1;
1491 ads_dump(ads, res);
1492 ads_msgfree(ads, res);
1493 ads_destroy(&ads);
1494 return 0;
1497 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1499 ADS_STRUCT *ads;
1500 ADS_STATUS rc;
1501 const char *servername, *printername;
1502 LDAPMessage *res = NULL;
1504 if (c->display_usage) {
1505 d_printf("Usage:\n"
1506 "net ads printer info [printername [servername]]\n"
1507 " Display printer info from AD\n"
1508 " printername\tPrinter name or wildcard\n"
1509 " servername\tName of the print server\n");
1510 return 0;
1513 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1514 return -1;
1517 if (argc > 0) {
1518 printername = argv[0];
1519 } else {
1520 printername = "*";
1523 if (argc > 1) {
1524 servername = argv[1];
1525 } else {
1526 servername = global_myname();
1529 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1531 if (!ADS_ERR_OK(rc)) {
1532 d_fprintf(stderr, "Server '%s' not found: %s\n",
1533 servername, ads_errstr(rc));
1534 ads_msgfree(ads, res);
1535 ads_destroy(&ads);
1536 return -1;
1539 if (ads_count_replies(ads, res) == 0) {
1540 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1541 ads_msgfree(ads, res);
1542 ads_destroy(&ads);
1543 return -1;
1546 ads_dump(ads, res);
1547 ads_msgfree(ads, res);
1548 ads_destroy(&ads);
1550 return 0;
1553 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1555 ADS_STRUCT *ads;
1556 ADS_STATUS rc;
1557 const char *servername, *printername;
1558 struct cli_state *cli;
1559 struct rpc_pipe_client *pipe_hnd;
1560 struct sockaddr_storage server_ss;
1561 NTSTATUS nt_status;
1562 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1563 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1564 char *prt_dn, *srv_dn, **srv_cn;
1565 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1566 LDAPMessage *res = NULL;
1568 if (argc < 1 || c->display_usage) {
1569 d_printf("Usage:\n"
1570 "net ads printer publish <printername> [servername]\n"
1571 " Publish printer in AD\n"
1572 " printername\tName of the printer\n"
1573 " servername\tName of the print server\n");
1574 talloc_destroy(mem_ctx);
1575 return -1;
1578 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1579 talloc_destroy(mem_ctx);
1580 return -1;
1583 printername = argv[0];
1585 if (argc == 2) {
1586 servername = argv[1];
1587 } else {
1588 servername = global_myname();
1591 /* Get printer data from SPOOLSS */
1593 resolve_name(servername, &server_ss, 0x20);
1595 nt_status = cli_full_connection(&cli, global_myname(), servername,
1596 &server_ss, 0,
1597 "IPC$", "IPC",
1598 c->opt_user_name, c->opt_workgroup,
1599 c->opt_password ? c->opt_password : "",
1600 CLI_FULL_CONNECTION_USE_KERBEROS,
1601 Undefined, NULL);
1603 if (NT_STATUS_IS_ERR(nt_status)) {
1604 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1605 "for %s\n", servername, printername);
1606 ads_destroy(&ads);
1607 talloc_destroy(mem_ctx);
1608 return -1;
1611 /* Publish on AD server */
1613 ads_find_machine_acct(ads, &res, servername);
1615 if (ads_count_replies(ads, res) == 0) {
1616 d_fprintf(stderr, "Could not find machine account for server %s\n",
1617 servername);
1618 ads_destroy(&ads);
1619 talloc_destroy(mem_ctx);
1620 return -1;
1623 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1624 srv_cn = ldap_explode_dn(srv_dn, 1);
1626 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1627 printername_escaped = escape_rdn_val_string_alloc(printername);
1628 if (!srv_cn_escaped || !printername_escaped) {
1629 SAFE_FREE(srv_cn_escaped);
1630 SAFE_FREE(printername_escaped);
1631 d_fprintf(stderr, "Internal error, out of memory!");
1632 ads_destroy(&ads);
1633 talloc_destroy(mem_ctx);
1634 return -1;
1637 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1639 SAFE_FREE(srv_cn_escaped);
1640 SAFE_FREE(printername_escaped);
1642 nt_status = cli_rpc_pipe_open_noauth(cli, &syntax_spoolss, &pipe_hnd);
1643 if (!NT_STATUS_IS_OK(nt_status)) {
1644 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1645 servername);
1646 SAFE_FREE(prt_dn);
1647 ads_destroy(&ads);
1648 talloc_destroy(mem_ctx);
1649 return -1;
1652 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1653 printername))) {
1654 SAFE_FREE(prt_dn);
1655 ads_destroy(&ads);
1656 talloc_destroy(mem_ctx);
1657 return -1;
1660 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1661 if (!ADS_ERR_OK(rc)) {
1662 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1663 SAFE_FREE(prt_dn);
1664 ads_destroy(&ads);
1665 talloc_destroy(mem_ctx);
1666 return -1;
1669 d_printf("published printer\n");
1670 SAFE_FREE(prt_dn);
1671 ads_destroy(&ads);
1672 talloc_destroy(mem_ctx);
1674 return 0;
1677 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1679 ADS_STRUCT *ads;
1680 ADS_STATUS rc;
1681 const char *servername;
1682 char *prt_dn;
1683 LDAPMessage *res = NULL;
1685 if (argc < 1 || c->display_usage) {
1686 d_printf("Usage:\n"
1687 "net ads printer remove <printername> [servername]\n"
1688 " Remove a printer from the AD\n"
1689 " printername\tName of the printer\n"
1690 " servername\tName of the print server\n");
1691 return -1;
1694 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1695 return -1;
1698 if (argc > 1) {
1699 servername = argv[1];
1700 } else {
1701 servername = global_myname();
1704 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1706 if (!ADS_ERR_OK(rc)) {
1707 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1708 ads_msgfree(ads, res);
1709 ads_destroy(&ads);
1710 return -1;
1713 if (ads_count_replies(ads, res) == 0) {
1714 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1715 ads_msgfree(ads, res);
1716 ads_destroy(&ads);
1717 return -1;
1720 prt_dn = ads_get_dn(ads, res);
1721 ads_msgfree(ads, res);
1722 rc = ads_del_dn(ads, prt_dn);
1723 ads_memfree(ads, prt_dn);
1725 if (!ADS_ERR_OK(rc)) {
1726 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1727 ads_destroy(&ads);
1728 return -1;
1731 ads_destroy(&ads);
1732 return 0;
1735 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1737 struct functable func[] = {
1739 "search",
1740 net_ads_printer_search,
1741 NET_TRANSPORT_ADS,
1742 "Search for a printer",
1743 "net ads printer search\n"
1744 " Search for a printer"
1747 "info",
1748 net_ads_printer_info,
1749 NET_TRANSPORT_ADS,
1750 "Display printer information",
1751 "net ads printer info\n"
1752 " Display printer information"
1755 "publish",
1756 net_ads_printer_publish,
1757 NET_TRANSPORT_ADS,
1758 "Publish a printer",
1759 "net ads printer publish\n"
1760 " Publish a printer"
1763 "remove",
1764 net_ads_printer_remove,
1765 NET_TRANSPORT_ADS,
1766 "Delete a printer",
1767 "net ads printer remove\n"
1768 " Delete a printer"
1770 {NULL, NULL, 0, NULL, NULL}
1773 return net_run_function(c, argc, argv, "net ads printer", func);
1777 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1779 ADS_STRUCT *ads;
1780 const char *auth_principal = c->opt_user_name;
1781 const char *auth_password = c->opt_password;
1782 char *realm = NULL;
1783 char *new_password = NULL;
1784 char *chr, *prompt;
1785 const char *user;
1786 ADS_STATUS ret;
1788 if (c->display_usage) {
1789 d_printf("Usage:\n"
1790 "net ads password <username>\n"
1791 " Change password for user\n"
1792 " username\tName of user to change password for\n");
1793 return 0;
1796 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1797 d_fprintf(stderr, "You must supply an administrator username/password\n");
1798 return -1;
1801 if (argc < 1) {
1802 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1803 return -1;
1806 user = argv[0];
1807 if (!strchr_m(user, '@')) {
1808 asprintf(&chr, "%s@%s", argv[0], lp_realm());
1809 user = chr;
1812 use_in_memory_ccache();
1813 chr = strchr_m(auth_principal, '@');
1814 if (chr) {
1815 realm = ++chr;
1816 } else {
1817 realm = lp_realm();
1820 /* use the realm so we can eventually change passwords for users
1821 in realms other than default */
1822 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1823 return -1;
1826 /* we don't actually need a full connect, but it's the easy way to
1827 fill in the KDC's addresss */
1828 ads_connect(ads);
1830 if (!ads->config.realm) {
1831 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1832 return -1;
1835 if (argv[1]) {
1836 new_password = (char *)argv[1];
1837 } else {
1838 asprintf(&prompt, "Enter new password for %s:", user);
1839 new_password = getpass(prompt);
1840 free(prompt);
1843 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1844 auth_password, user, new_password, ads->auth.time_offset);
1845 if (!ADS_ERR_OK(ret)) {
1846 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1847 ads_destroy(&ads);
1848 return -1;
1851 d_printf("Password change for %s completed.\n", user);
1852 ads_destroy(&ads);
1854 return 0;
1857 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1859 ADS_STRUCT *ads;
1860 char *host_principal;
1861 fstring my_name;
1862 ADS_STATUS ret;
1864 if (c->display_usage) {
1865 d_printf("Usage:\n"
1866 "net ads changetrustpw\n"
1867 " Change the machine account's trust password\n");
1868 return 0;
1871 if (!secrets_init()) {
1872 DEBUG(1,("Failed to initialise secrets database\n"));
1873 return -1;
1876 net_use_krb_machine_account(c);
1878 use_in_memory_ccache();
1880 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1881 return -1;
1884 fstrcpy(my_name, global_myname());
1885 strlower_m(my_name);
1886 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1887 d_printf("Changing password for principal: %s\n", host_principal);
1889 ret = ads_change_trust_account_password(ads, host_principal);
1891 if (!ADS_ERR_OK(ret)) {
1892 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1893 ads_destroy(&ads);
1894 SAFE_FREE(host_principal);
1895 return -1;
1898 d_printf("Password change for principal %s succeeded.\n", host_principal);
1900 if (lp_use_kerberos_keytab()) {
1901 d_printf("Attempting to update system keytab with new password.\n");
1902 if (ads_keytab_create_default(ads)) {
1903 d_printf("Failed to update system keytab.\n");
1907 ads_destroy(&ads);
1908 SAFE_FREE(host_principal);
1910 return 0;
1914 help for net ads search
1916 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
1918 d_printf(
1919 "\nnet ads search <expression> <attributes...>\n"
1920 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1921 "The expression is a standard LDAP search expression, and the\n"
1922 "attributes are a list of LDAP fields to show in the results.\n\n"
1923 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1925 net_common_flags_usage(c, argc, argv);
1926 return -1;
1931 general ADS search function. Useful in diagnosing problems in ADS
1933 static int net_ads_search(struct net_context *c, int argc, const char **argv)
1935 ADS_STRUCT *ads;
1936 ADS_STATUS rc;
1937 const char *ldap_exp;
1938 const char **attrs;
1939 LDAPMessage *res = NULL;
1941 if (argc < 1 || c->display_usage) {
1942 return net_ads_search_usage(c, argc, argv);
1945 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1946 return -1;
1949 ldap_exp = argv[0];
1950 attrs = (argv + 1);
1952 rc = ads_do_search_all(ads, ads->config.bind_path,
1953 LDAP_SCOPE_SUBTREE,
1954 ldap_exp, attrs, &res);
1955 if (!ADS_ERR_OK(rc)) {
1956 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1957 ads_destroy(&ads);
1958 return -1;
1961 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1963 /* dump the results */
1964 ads_dump(ads, res);
1966 ads_msgfree(ads, res);
1967 ads_destroy(&ads);
1969 return 0;
1974 help for net ads search
1976 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
1978 d_printf(
1979 "\nnet ads dn <dn> <attributes...>\n"
1980 "\nperform a raw LDAP search on a ADS server and dump the results\n"
1981 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
1982 "to show in the results\n\n"
1983 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1984 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1986 net_common_flags_usage(c, argc, argv);
1987 return -1;
1992 general ADS search function. Useful in diagnosing problems in ADS
1994 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
1996 ADS_STRUCT *ads;
1997 ADS_STATUS rc;
1998 const char *dn;
1999 const char **attrs;
2000 LDAPMessage *res = NULL;
2002 if (argc < 1 || c->display_usage) {
2003 return net_ads_dn_usage(c, argc, argv);
2006 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2007 return -1;
2010 dn = argv[0];
2011 attrs = (argv + 1);
2013 rc = ads_do_search_all(ads, dn,
2014 LDAP_SCOPE_BASE,
2015 "(objectclass=*)", attrs, &res);
2016 if (!ADS_ERR_OK(rc)) {
2017 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2018 ads_destroy(&ads);
2019 return -1;
2022 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2024 /* dump the results */
2025 ads_dump(ads, res);
2027 ads_msgfree(ads, res);
2028 ads_destroy(&ads);
2030 return 0;
2034 help for net ads sid search
2036 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2038 d_printf(
2039 "\nnet ads sid <sid> <attributes...>\n"
2040 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2041 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2042 "to show in the results\n\n"
2043 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2045 net_common_flags_usage(c, argc, argv);
2046 return -1;
2051 general ADS search function. Useful in diagnosing problems in ADS
2053 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2055 ADS_STRUCT *ads;
2056 ADS_STATUS rc;
2057 const char *sid_string;
2058 const char **attrs;
2059 LDAPMessage *res = NULL;
2060 DOM_SID sid;
2062 if (argc < 1 || c->display_usage) {
2063 return net_ads_sid_usage(c, argc, argv);
2066 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2067 return -1;
2070 sid_string = argv[0];
2071 attrs = (argv + 1);
2073 if (!string_to_sid(&sid, sid_string)) {
2074 d_fprintf(stderr, "could not convert sid\n");
2075 ads_destroy(&ads);
2076 return -1;
2079 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2080 if (!ADS_ERR_OK(rc)) {
2081 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2082 ads_destroy(&ads);
2083 return -1;
2086 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2088 /* dump the results */
2089 ads_dump(ads, res);
2091 ads_msgfree(ads, res);
2092 ads_destroy(&ads);
2094 return 0;
2097 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2099 int ret;
2100 ADS_STRUCT *ads;
2102 if (c->display_usage) {
2103 d_printf("Usage:\n"
2104 "net ads keytab flush\n"
2105 " Delete the whole keytab\n");
2106 return 0;
2109 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2110 return -1;
2112 ret = ads_keytab_flush(ads);
2113 ads_destroy(&ads);
2114 return ret;
2117 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2119 int i;
2120 int ret = 0;
2121 ADS_STRUCT *ads;
2123 if (c->display_usage) {
2124 d_printf("Usage:\n"
2125 "net ads keytab add <principal> [principal ...]\n"
2126 " Add principals to local keytab\n"
2127 " principal\tKerberos principal to add to "
2128 "keytab\n");
2129 return 0;
2132 d_printf("Processing principals to add...\n");
2133 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2134 return -1;
2136 for (i = 0; i < argc; i++) {
2137 ret |= ads_keytab_add_entry(ads, argv[i]);
2139 ads_destroy(&ads);
2140 return ret;
2143 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2145 ADS_STRUCT *ads;
2146 int ret;
2148 if (c->display_usage) {
2149 d_printf("Usage:\n"
2150 "net ads keytab create\n"
2151 " Create new default keytab\n");
2152 return 0;
2155 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2156 return -1;
2158 ret = ads_keytab_create_default(ads);
2159 ads_destroy(&ads);
2160 return ret;
2163 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2165 const char *keytab = NULL;
2167 if (c->display_usage) {
2168 d_printf("Usage:\n"
2169 "net ads keytab list [keytab]\n"
2170 " List a local keytab\n"
2171 " keytab\tKeytab to list\n");
2172 return 0;
2175 if (argc >= 1) {
2176 keytab = argv[0];
2179 return ads_keytab_list(keytab);
2183 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2185 struct functable func[] = {
2187 "add",
2188 net_ads_keytab_add,
2189 NET_TRANSPORT_ADS,
2190 "Add a service principal",
2191 "net ads keytab add\n"
2192 " Add a service principal"
2195 "create",
2196 net_ads_keytab_create,
2197 NET_TRANSPORT_ADS,
2198 "Create a fresh keytab",
2199 "net ads keytab create\n"
2200 " Create a fresh keytab"
2203 "flush",
2204 net_ads_keytab_flush,
2205 NET_TRANSPORT_ADS,
2206 "Remove all keytab entries",
2207 "net ads keytab flush\n"
2208 " Remove all keytab entries"
2211 "list",
2212 net_ads_keytab_list,
2213 NET_TRANSPORT_ADS,
2214 "List a keytab",
2215 "net ads keytab list\n"
2216 " List a keytab"
2218 {NULL, NULL, 0, NULL, NULL}
2221 if (!lp_use_kerberos_keytab()) {
2222 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2223 use keytab functions.\n");
2226 return net_run_function(c, argc, argv, "net ads keytab", func);
2229 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2231 int ret = -1;
2233 if (c->display_usage) {
2234 d_printf("Usage:\n"
2235 "net ads kerberos renew\n"
2236 " Renew TGT from existing credential cache\n");
2237 return 0;
2240 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2241 if (ret) {
2242 d_printf("failed to renew kerberos ticket: %s\n",
2243 error_message(ret));
2245 return ret;
2248 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2250 struct PAC_DATA *pac = NULL;
2251 struct PAC_LOGON_INFO *info = NULL;
2252 TALLOC_CTX *mem_ctx = NULL;
2253 NTSTATUS status;
2254 int ret = -1;
2256 if (c->display_usage) {
2257 d_printf("Usage:\n"
2258 "net ads kerberos pac\n"
2259 " Dump the Kerberos PAC\n");
2260 return 0;
2263 mem_ctx = talloc_init("net_ads_kerberos_pac");
2264 if (!mem_ctx) {
2265 goto out;
2268 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2270 status = kerberos_return_pac(mem_ctx,
2271 c->opt_user_name,
2272 c->opt_password,
2274 NULL,
2275 NULL,
2276 NULL,
2277 true,
2278 true,
2279 2592000, /* one month */
2280 &pac);
2281 if (!NT_STATUS_IS_OK(status)) {
2282 d_printf("failed to query kerberos PAC: %s\n",
2283 nt_errstr(status));
2284 goto out;
2287 info = get_logon_info_from_pac(pac);
2288 if (info) {
2289 const char *s;
2290 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2291 d_printf("The Pac: %s\n", s);
2294 ret = 0;
2295 out:
2296 TALLOC_FREE(mem_ctx);
2297 return ret;
2300 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2302 TALLOC_CTX *mem_ctx = NULL;
2303 int ret = -1;
2304 NTSTATUS status;
2306 if (c->display_usage) {
2307 d_printf("Usage:\n"
2308 "net ads kerberos kinit\n"
2309 " Get Ticket Granting Ticket (TGT) for the user\n");
2310 return 0;
2313 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2314 if (!mem_ctx) {
2315 goto out;
2318 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2320 ret = kerberos_kinit_password_ext(c->opt_user_name,
2321 c->opt_password,
2323 NULL,
2324 NULL,
2325 NULL,
2326 true,
2327 true,
2328 2592000, /* one month */
2329 &status);
2330 if (ret) {
2331 d_printf("failed to kinit password: %s\n",
2332 nt_errstr(status));
2334 out:
2335 return ret;
2338 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2340 struct functable func[] = {
2342 "kinit",
2343 net_ads_kerberos_kinit,
2344 NET_TRANSPORT_ADS,
2345 "Retrieve Ticket Granting Ticket (TGT)",
2346 "net ads kerberos kinit\n"
2347 " Receive Ticket Granting Ticket (TGT)"
2350 "renew",
2351 net_ads_kerberos_renew,
2352 NET_TRANSPORT_ADS,
2353 "Renew Ticket Granting Ticket from credential cache"
2354 "net ads kerberos renew\n"
2355 " Renew Ticket Granting Ticket from credential cache"
2358 "pac",
2359 net_ads_kerberos_pac,
2360 NET_TRANSPORT_ADS,
2361 "Dump Kerberos PAC",
2362 "net ads kerberos pac\n"
2363 " Dump Kerberos PAC"
2365 {NULL, NULL, 0, NULL, NULL}
2368 return net_run_function(c, argc, argv, "net ads kerberos", func);
2371 int net_ads(struct net_context *c, int argc, const char **argv)
2373 struct functable func[] = {
2375 "info",
2376 net_ads_info,
2377 NET_TRANSPORT_ADS,
2378 "Display details on remote ADS server",
2379 "net ads info\n"
2380 " Display details on remote ADS server"
2383 "join",
2384 net_ads_join,
2385 NET_TRANSPORT_ADS,
2386 "Join the local machine to ADS realm",
2387 "net ads join\n"
2388 " Join the local machine to ADS realm"
2391 "testjoin",
2392 net_ads_testjoin,
2393 NET_TRANSPORT_ADS,
2394 "Validate machine account",
2395 "net ads testjoin\n"
2396 " Validate machine account"
2399 "leave",
2400 net_ads_leave,
2401 NET_TRANSPORT_ADS,
2402 "Remove the local machine from ADS",
2403 "net ads leave\n"
2404 " Remove the local machine from ADS"
2407 "status",
2408 net_ads_status,
2409 NET_TRANSPORT_ADS,
2410 "Display machine account details",
2411 "net ads status\n"
2412 " Display machine account details"
2415 "user",
2416 net_ads_user,
2417 NET_TRANSPORT_ADS,
2418 "List/modify users",
2419 "net ads user\n"
2420 " List/modify users"
2423 "group",
2424 net_ads_group,
2425 NET_TRANSPORT_ADS,
2426 "List/modify groups",
2427 "net ads group\n"
2428 " List/modify groups"
2431 "dns",
2432 net_ads_dns,
2433 NET_TRANSPORT_ADS,
2434 "Issue dynamic DNS update",
2435 "net ads dns\n"
2436 " Issue dynamic DNS update"
2439 "password",
2440 net_ads_password,
2441 NET_TRANSPORT_ADS,
2442 "Change user passwords",
2443 "net ads password\n"
2444 " Change user passwords"
2447 "changetrustpw",
2448 net_ads_changetrustpw,
2449 NET_TRANSPORT_ADS,
2450 "Change trust account password",
2451 "net ads changetrustpw\n"
2452 " Change trust account password"
2455 "printer",
2456 net_ads_printer,
2457 NET_TRANSPORT_ADS,
2458 "List/modify printer entries",
2459 "net ads printer\n"
2460 " List/modify printer entries"
2463 "search",
2464 net_ads_search,
2465 NET_TRANSPORT_ADS,
2466 "Issue LDAP search using filter",
2467 "net ads search\n"
2468 " Issue LDAP search using filter"
2471 "dn",
2472 net_ads_dn,
2473 NET_TRANSPORT_ADS,
2474 "Issue LDAP search by DN",
2475 "net ads dn\n"
2476 " Issue LDAP search by DN"
2479 "sid",
2480 net_ads_sid,
2481 NET_TRANSPORT_ADS,
2482 "Issue LDAP search by SID",
2483 "net ads sid\n"
2484 " Issue LDAP search by SID"
2487 "workgroup",
2488 net_ads_workgroup,
2489 NET_TRANSPORT_ADS,
2490 "Display workgroup name",
2491 "net ads workgroup\n"
2492 " Display the workgroup name"
2495 "lookup",
2496 net_ads_lookup,
2497 NET_TRANSPORT_ADS,
2498 "Perfom CLDAP query on DC",
2499 "net ads lookup\n"
2500 " Find the ADS DC using CLDAP lookups"
2503 "keytab",
2504 net_ads_keytab,
2505 NET_TRANSPORT_ADS,
2506 "Manage local keytab file",
2507 "net ads keytab\n"
2508 " Manage local keytab file"
2511 "gpo",
2512 net_ads_gpo,
2513 NET_TRANSPORT_ADS,
2514 "Manage group policy objects",
2515 "net ads gpo\n"
2516 " Manage group policy objects"
2519 "kerberos",
2520 net_ads_kerberos,
2521 NET_TRANSPORT_ADS,
2522 "Manage kerberos keytab",
2523 "net ads kerberos\n"
2524 " Manage kerberos keytab"
2526 {NULL, NULL, 0, NULL, NULL}
2529 return net_run_function(c, argc, argv, "net ads", func);
2532 #else
2534 static int net_ads_noads(void)
2536 d_fprintf(stderr, "ADS support not compiled in\n");
2537 return -1;
2540 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2542 return net_ads_noads();
2545 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2547 return net_ads_noads();
2550 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2552 return net_ads_noads();
2555 int net_ads_join(struct net_context *c, int argc, const char **argv)
2557 return net_ads_noads();
2560 int net_ads_user(struct net_context *c, int argc, const char **argv)
2562 return net_ads_noads();
2565 int net_ads_group(struct net_context *c, int argc, const char **argv)
2567 return net_ads_noads();
2570 /* this one shouldn't display a message */
2571 int net_ads_check(struct net_context *c)
2573 return -1;
2576 int net_ads_check_our_domain(struct net_context *c)
2578 return -1;
2581 int net_ads(struct net_context *c, int argc, const char **argv)
2583 return net_ads_noads();
2586 #endif /* WITH_ADS */