TEMP: Rollup of lots of changes so they don't get lost
[Samba/vfs_proxy.git] / source3 / utils / net_ads.c
blobb03fefe14a1362e15c85d08441bc63e84fd8bec5
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"
25 #include "librpc/gen_ndr/ndr_krb5pac.h"
27 #ifdef HAVE_ADS
29 /* when we do not have sufficient input parameters to contact a remote domain
30 * we always fall back to our own realm - Guenther*/
32 static const char *assume_own_realm(struct net_context *c)
34 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
35 return lp_realm();
38 return NULL;
42 do a cldap netlogon query
44 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
46 char addr[INET6_ADDRSTRLEN];
47 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
49 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
50 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
51 d_fprintf(stderr, "CLDAP query failed!\n");
52 return -1;
55 d_printf("Information for Domain Controller: %s\n\n",
56 addr);
58 d_printf("Response Type: ");
59 switch (reply.command) {
60 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
61 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
62 break;
63 case LOGON_SAM_LOGON_RESPONSE_EX:
64 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
65 break;
66 default:
67 d_printf("0x%x\n", reply.command);
68 break;
71 d_printf("GUID: %s\n", GUID_string(talloc_tos(), &reply.domain_uuid));
73 d_printf("Flags:\n"
74 "\tIs a PDC: %s\n"
75 "\tIs a GC of the forest: %s\n"
76 "\tIs an LDAP server: %s\n"
77 "\tSupports DS: %s\n"
78 "\tIs running a KDC: %s\n"
79 "\tIs running time services: %s\n"
80 "\tIs the closest DC: %s\n"
81 "\tIs writable: %s\n"
82 "\tHas a hardware clock: %s\n"
83 "\tIs a non-domain NC serviced by LDAP server: %s\n"
84 "\tIs NT6 DC that has some secrets: %s\n"
85 "\tIs NT6 DC that has all secrets: %s\n",
86 (reply.server_type & NBT_SERVER_PDC) ? "yes" : "no",
87 (reply.server_type & NBT_SERVER_GC) ? "yes" : "no",
88 (reply.server_type & NBT_SERVER_LDAP) ? "yes" : "no",
89 (reply.server_type & NBT_SERVER_DS) ? "yes" : "no",
90 (reply.server_type & NBT_SERVER_KDC) ? "yes" : "no",
91 (reply.server_type & NBT_SERVER_TIMESERV) ? "yes" : "no",
92 (reply.server_type & NBT_SERVER_CLOSEST) ? "yes" : "no",
93 (reply.server_type & NBT_SERVER_WRITABLE) ? "yes" : "no",
94 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? "yes" : "no",
95 (reply.server_type & NBT_SERVER_NDNC) ? "yes" : "no",
96 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? "yes" : "no",
97 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? "yes" : "no");
100 printf("Forest:\t\t\t%s\n", reply.forest);
101 printf("Domain:\t\t\t%s\n", reply.dns_domain);
102 printf("Domain Controller:\t%s\n", reply.pdc_dns_name);
104 printf("Pre-Win2k Domain:\t%s\n", reply.domain);
105 printf("Pre-Win2k Hostname:\t%s\n", reply.pdc_name);
107 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
109 printf("Server Site Name :\t\t%s\n", reply.server_site);
110 printf("Client Site Name :\t\t%s\n", reply.client_site);
112 d_printf("NT Version: %d\n", reply.nt_version);
113 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
114 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
116 return 0;
120 this implements the CLDAP based netlogon lookup requests
121 for finding the domain controller of a ADS domain
123 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
125 ADS_STRUCT *ads;
127 if (c->display_usage) {
128 d_printf("Usage:\n"
129 "net ads lookup\n"
130 " Find the ADS DC using CLDAP lookup.\n");
131 return 0;
134 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
135 d_fprintf(stderr, "Didn't find the cldap server!\n");
136 return -1;
139 if (!ads->config.realm) {
140 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
141 ads->ldap.port = 389;
144 return net_ads_cldap_netlogon(c, ads);
149 static int net_ads_info(struct net_context *c, int argc, const char **argv)
151 ADS_STRUCT *ads;
152 char addr[INET6_ADDRSTRLEN];
154 if (c->display_usage) {
155 d_printf("Usage:\n"
156 "net ads info\n"
157 " Display information about an Active Directory "
158 "server.\n");
159 return 0;
162 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
163 d_fprintf(stderr, "Didn't find the ldap server!\n");
164 return -1;
167 if (!ads || !ads->config.realm) {
168 d_fprintf(stderr, "Didn't find the ldap server!\n");
169 return -1;
172 /* Try to set the server's current time since we didn't do a full
173 TCP LDAP session initially */
175 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
176 d_fprintf( stderr, "Failed to get server's current time!\n");
179 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
181 d_printf("LDAP server: %s\n", addr);
182 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
183 d_printf("Realm: %s\n", ads->config.realm);
184 d_printf("Bind Path: %s\n", ads->config.bind_path);
185 d_printf("LDAP port: %d\n", ads->ldap.port);
186 d_printf("Server time: %s\n",
187 http_timestring(talloc_tos(), ads->config.current_time));
189 d_printf("KDC server: %s\n", ads->auth.kdc_server );
190 d_printf("Server time offset: %d\n", ads->auth.time_offset );
192 return 0;
195 static void use_in_memory_ccache(void) {
196 /* Use in-memory credentials cache so we do not interfere with
197 * existing credentials */
198 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
201 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
202 uint32 auth_flags, ADS_STRUCT **ads_ret)
204 ADS_STRUCT *ads = NULL;
205 ADS_STATUS status;
206 bool need_password = false;
207 bool second_time = false;
208 char *cp;
209 const char *realm = NULL;
210 bool tried_closest_dc = false;
212 /* lp_realm() should be handled by a command line param,
213 However, the join requires that realm be set in smb.conf
214 and compares our realm with the remote server's so this is
215 ok until someone needs more flexibility */
217 *ads_ret = NULL;
219 retry_connect:
220 if (only_own_domain) {
221 realm = lp_realm();
222 } else {
223 realm = assume_own_realm(c);
226 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
228 if (!c->opt_user_name) {
229 c->opt_user_name = "administrator";
232 if (c->opt_user_specified) {
233 need_password = true;
236 retry:
237 if (!c->opt_password && need_password && !c->opt_machine_pass) {
238 c->opt_password = net_prompt_pass(c, c->opt_user_name);
239 if (!c->opt_password) {
240 ads_destroy(&ads);
241 return ADS_ERROR(LDAP_NO_MEMORY);
245 if (c->opt_password) {
246 use_in_memory_ccache();
247 SAFE_FREE(ads->auth.password);
248 ads->auth.password = smb_xstrdup(c->opt_password);
251 ads->auth.flags |= auth_flags;
252 SAFE_FREE(ads->auth.user_name);
253 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
256 * If the username is of the form "name@realm",
257 * extract the realm and convert to upper case.
258 * This is only used to establish the connection.
260 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
261 *cp++ = '\0';
262 SAFE_FREE(ads->auth.realm);
263 ads->auth.realm = smb_xstrdup(cp);
264 strupper_m(ads->auth.realm);
267 status = ads_connect(ads);
269 if (!ADS_ERR_OK(status)) {
271 if (NT_STATUS_EQUAL(ads_ntstatus(status),
272 NT_STATUS_NO_LOGON_SERVERS)) {
273 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
274 ads_destroy(&ads);
275 return status;
278 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
279 need_password = true;
280 second_time = true;
281 goto retry;
282 } else {
283 ads_destroy(&ads);
284 return status;
288 /* when contacting our own domain, make sure we use the closest DC.
289 * This is done by reconnecting to ADS because only the first call to
290 * ads_connect will give us our own sitename */
292 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
294 tried_closest_dc = true; /* avoid loop */
296 if (!ads->config.tried_closest_dc) {
298 namecache_delete(ads->server.realm, 0x1C);
299 namecache_delete(ads->server.workgroup, 0x1C);
301 ads_destroy(&ads);
302 ads = NULL;
304 goto retry_connect;
308 *ads_ret = ads;
309 return status;
312 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
314 return ads_startup_int(c, only_own_domain, 0, ads);
317 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
319 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
323 Check to see if connection can be made via ads.
324 ads_startup() stores the password in opt_password if it needs to so
325 that rpc or rap can use it without re-prompting.
327 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
329 ADS_STRUCT *ads;
330 ADS_STATUS status;
332 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
333 return -1;
336 ads->auth.flags |= ADS_AUTH_NO_BIND;
338 status = ads_connect(ads);
339 if ( !ADS_ERR_OK(status) ) {
340 return -1;
343 ads_destroy(&ads);
344 return 0;
347 int net_ads_check_our_domain(struct net_context *c)
349 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
352 int net_ads_check(struct net_context *c)
354 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
358 determine the netbios workgroup name for a domain
360 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
362 ADS_STRUCT *ads;
363 char addr[INET6_ADDRSTRLEN];
364 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
366 if (c->display_usage) {
367 d_printf("Usage:\n"
368 "net ads workgroup\n"
369 " Print the workgroup name\n");
370 return 0;
373 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
374 d_fprintf(stderr, "Didn't find the cldap server!\n");
375 return -1;
378 if (!ads->config.realm) {
379 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
380 ads->ldap.port = 389;
383 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
384 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
385 d_fprintf(stderr, "CLDAP query failed!\n");
386 return -1;
389 d_printf("Workgroup: %s\n", reply.domain);
391 ads_destroy(&ads);
393 return 0;
398 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
400 char **disp_fields = (char **) data_area;
402 if (!field) { /* must be end of record */
403 if (disp_fields[0]) {
404 if (!strchr_m(disp_fields[0], '$')) {
405 if (disp_fields[1])
406 d_printf("%-21.21s %s\n",
407 disp_fields[0], disp_fields[1]);
408 else
409 d_printf("%s\n", disp_fields[0]);
412 SAFE_FREE(disp_fields[0]);
413 SAFE_FREE(disp_fields[1]);
414 return true;
416 if (!values) /* must be new field, indicate string field */
417 return true;
418 if (StrCaseCmp(field, "sAMAccountName") == 0) {
419 disp_fields[0] = SMB_STRDUP((char *) values[0]);
421 if (StrCaseCmp(field, "description") == 0)
422 disp_fields[1] = SMB_STRDUP((char *) values[0]);
423 return true;
426 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
428 return net_user_usage(c, argc, argv);
431 static int ads_user_add(struct net_context *c, int argc, const char **argv)
433 ADS_STRUCT *ads;
434 ADS_STATUS status;
435 char *upn, *userdn;
436 LDAPMessage *res=NULL;
437 int rc = -1;
438 char *ou_str = NULL;
440 if (argc < 1 || c->display_usage)
441 return net_ads_user_usage(c, argc, argv);
443 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
444 return -1;
447 status = ads_find_user_acct(ads, &res, argv[0]);
449 if (!ADS_ERR_OK(status)) {
450 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
451 goto done;
454 if (ads_count_replies(ads, res)) {
455 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
456 goto done;
459 if (c->opt_container) {
460 ou_str = SMB_STRDUP(c->opt_container);
461 } else {
462 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
465 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
467 if (!ADS_ERR_OK(status)) {
468 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
469 ads_errstr(status));
470 goto done;
473 /* if no password is to be set, we're done */
474 if (argc == 1) {
475 d_printf("User %s added\n", argv[0]);
476 rc = 0;
477 goto done;
480 /* try setting the password */
481 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
482 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
483 ads->auth.time_offset);
484 SAFE_FREE(upn);
485 if (ADS_ERR_OK(status)) {
486 d_printf("User %s added\n", argv[0]);
487 rc = 0;
488 goto done;
491 /* password didn't set, delete account */
492 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
493 argv[0], ads_errstr(status));
494 ads_msgfree(ads, res);
495 status=ads_find_user_acct(ads, &res, argv[0]);
496 if (ADS_ERR_OK(status)) {
497 userdn = ads_get_dn(ads, res);
498 ads_del_dn(ads, userdn);
499 ads_memfree(ads, userdn);
502 done:
503 if (res)
504 ads_msgfree(ads, res);
505 ads_destroy(&ads);
506 SAFE_FREE(ou_str);
507 return rc;
510 static int ads_user_info(struct net_context *c, int argc, const char **argv)
512 ADS_STRUCT *ads;
513 ADS_STATUS rc;
514 LDAPMessage *res;
515 const char *attrs[] = {"memberOf", NULL};
516 char *searchstring=NULL;
517 char **grouplist;
518 char *escaped_user;
520 if (argc < 1 || c->display_usage) {
521 return net_ads_user_usage(c, argc, argv);
524 escaped_user = escape_ldap_string_alloc(argv[0]);
526 if (!escaped_user) {
527 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
528 return -1;
531 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
532 SAFE_FREE(escaped_user);
533 return -1;
536 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
537 rc = ads_search(ads, &res, searchstring, attrs);
538 SAFE_FREE(searchstring);
540 if (!ADS_ERR_OK(rc)) {
541 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
542 ads_destroy(&ads);
543 SAFE_FREE(escaped_user);
544 return -1;
547 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
548 (LDAPMessage *)res, "memberOf");
550 if (grouplist) {
551 int i;
552 char **groupname;
553 for (i=0;grouplist[i];i++) {
554 groupname = ldap_explode_dn(grouplist[i], 1);
555 d_printf("%s\n", groupname[0]);
556 ldap_value_free(groupname);
558 ldap_value_free(grouplist);
561 ads_msgfree(ads, res);
562 ads_destroy(&ads);
563 SAFE_FREE(escaped_user);
564 return 0;
567 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
569 ADS_STRUCT *ads;
570 ADS_STATUS rc;
571 LDAPMessage *res = NULL;
572 char *userdn;
574 if (argc < 1) {
575 return net_ads_user_usage(c, argc, argv);
578 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
579 return -1;
582 rc = ads_find_user_acct(ads, &res, argv[0]);
583 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
584 d_printf("User %s does not exist.\n", argv[0]);
585 ads_msgfree(ads, res);
586 ads_destroy(&ads);
587 return -1;
589 userdn = ads_get_dn(ads, res);
590 ads_msgfree(ads, res);
591 rc = ads_del_dn(ads, userdn);
592 ads_memfree(ads, userdn);
593 if (ADS_ERR_OK(rc)) {
594 d_printf("User %s deleted\n", argv[0]);
595 ads_destroy(&ads);
596 return 0;
598 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
599 ads_errstr(rc));
600 ads_destroy(&ads);
601 return -1;
604 int net_ads_user(struct net_context *c, int argc, const char **argv)
606 struct functable func[] = {
608 "add",
609 ads_user_add,
610 NET_TRANSPORT_ADS,
611 "Add an AD user",
612 "net ads user add\n"
613 " Add an AD user"
616 "info",
617 ads_user_info,
618 NET_TRANSPORT_ADS,
619 "Display information about an AD user",
620 "net ads user info\n"
621 " Display information about an AD user"
624 "delete",
625 ads_user_delete,
626 NET_TRANSPORT_ADS,
627 "Delete an AD user",
628 "net ads user delete\n"
629 " Delete an AD user"
631 {NULL, NULL, 0, NULL, NULL}
633 ADS_STRUCT *ads;
634 ADS_STATUS rc;
635 const char *shortattrs[] = {"sAMAccountName", NULL};
636 const char *longattrs[] = {"sAMAccountName", "description", NULL};
637 char *disp_fields[2] = {NULL, NULL};
639 if (argc == 0) {
640 if (c->display_usage) {
641 d_printf("Usage:\n");
642 d_printf("net ads user\n"
643 " List AD users\n");
644 net_display_usage_from_functable(func);
645 return 0;
648 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
649 return -1;
652 if (c->opt_long_list_entries)
653 d_printf("\nUser name Comment"
654 "\n-----------------------------\n");
656 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
657 LDAP_SCOPE_SUBTREE,
658 "(objectCategory=user)",
659 c->opt_long_list_entries ? longattrs :
660 shortattrs, usergrp_display,
661 disp_fields);
662 ads_destroy(&ads);
663 return ADS_ERR_OK(rc) ? 0 : -1;
666 return net_run_function(c, argc, argv, "net ads user", func);
669 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
671 return net_group_usage(c, argc, argv);
674 static int ads_group_add(struct net_context *c, int argc, const char **argv)
676 ADS_STRUCT *ads;
677 ADS_STATUS status;
678 LDAPMessage *res=NULL;
679 int rc = -1;
680 char *ou_str = NULL;
682 if (argc < 1 || c->display_usage) {
683 return net_ads_group_usage(c, argc, argv);
686 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
687 return -1;
690 status = ads_find_user_acct(ads, &res, argv[0]);
692 if (!ADS_ERR_OK(status)) {
693 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
694 goto done;
697 if (ads_count_replies(ads, res)) {
698 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
699 goto done;
702 if (c->opt_container) {
703 ou_str = SMB_STRDUP(c->opt_container);
704 } else {
705 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
708 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
710 if (ADS_ERR_OK(status)) {
711 d_printf("Group %s added\n", argv[0]);
712 rc = 0;
713 } else {
714 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
715 ads_errstr(status));
718 done:
719 if (res)
720 ads_msgfree(ads, res);
721 ads_destroy(&ads);
722 SAFE_FREE(ou_str);
723 return rc;
726 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
728 ADS_STRUCT *ads;
729 ADS_STATUS rc;
730 LDAPMessage *res = NULL;
731 char *groupdn;
733 if (argc < 1 || c->display_usage) {
734 return net_ads_group_usage(c, argc, argv);
737 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
738 return -1;
741 rc = ads_find_user_acct(ads, &res, argv[0]);
742 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
743 d_printf("Group %s does not exist.\n", argv[0]);
744 ads_msgfree(ads, res);
745 ads_destroy(&ads);
746 return -1;
748 groupdn = ads_get_dn(ads, res);
749 ads_msgfree(ads, res);
750 rc = ads_del_dn(ads, groupdn);
751 ads_memfree(ads, groupdn);
752 if (ADS_ERR_OK(rc)) {
753 d_printf("Group %s deleted\n", argv[0]);
754 ads_destroy(&ads);
755 return 0;
757 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
758 ads_errstr(rc));
759 ads_destroy(&ads);
760 return -1;
763 int net_ads_group(struct net_context *c, int argc, const char **argv)
765 struct functable func[] = {
767 "add",
768 ads_group_add,
769 NET_TRANSPORT_ADS,
770 "Add an AD group",
771 "net ads group add\n"
772 " Add an AD group"
775 "delete",
776 ads_group_delete,
777 NET_TRANSPORT_ADS,
778 "Delete an AD group",
779 "net ads group delete\n"
780 " Delete an AD group"
782 {NULL, NULL, 0, NULL, NULL}
784 ADS_STRUCT *ads;
785 ADS_STATUS rc;
786 const char *shortattrs[] = {"sAMAccountName", NULL};
787 const char *longattrs[] = {"sAMAccountName", "description", NULL};
788 char *disp_fields[2] = {NULL, NULL};
790 if (argc == 0) {
791 if (c->display_usage) {
792 d_printf("Usage:\n");
793 d_printf("net ads group\n"
794 " List AD groups\n");
795 net_display_usage_from_functable(func);
796 return 0;
799 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
800 return -1;
803 if (c->opt_long_list_entries)
804 d_printf("\nGroup name Comment"
805 "\n-----------------------------\n");
806 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
807 LDAP_SCOPE_SUBTREE,
808 "(objectCategory=group)",
809 c->opt_long_list_entries ? longattrs :
810 shortattrs, usergrp_display,
811 disp_fields);
813 ads_destroy(&ads);
814 return ADS_ERR_OK(rc) ? 0 : -1;
816 return net_run_function(c, argc, argv, "net ads group", func);
819 static int net_ads_status(struct net_context *c, int argc, const char **argv)
821 ADS_STRUCT *ads;
822 ADS_STATUS rc;
823 LDAPMessage *res;
825 if (c->display_usage) {
826 d_printf("Usage:\n"
827 "net ads status\n"
828 " Display machine account details\n");
829 return 0;
832 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
833 return -1;
836 rc = ads_find_machine_acct(ads, &res, global_myname());
837 if (!ADS_ERR_OK(rc)) {
838 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
839 ads_destroy(&ads);
840 return -1;
843 if (ads_count_replies(ads, res) == 0) {
844 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
845 ads_destroy(&ads);
846 return -1;
849 ads_dump(ads, res);
850 ads_destroy(&ads);
851 return 0;
854 /*******************************************************************
855 Leave an AD domain. Windows XP disables the machine account.
856 We'll try the same. The old code would do an LDAP delete.
857 That only worked using the machine creds because added the machine
858 with full control to the computer object's ACL.
859 *******************************************************************/
861 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
863 TALLOC_CTX *ctx;
864 struct libnet_UnjoinCtx *r = NULL;
865 WERROR werr;
867 if (c->display_usage) {
868 d_printf("Usage:\n"
869 "net ads leave\n"
870 " Leave an AD domain\n");
871 return 0;
874 if (!*lp_realm()) {
875 d_fprintf(stderr, "No realm set, are we joined ?\n");
876 return -1;
879 if (!(ctx = talloc_init("net_ads_leave"))) {
880 d_fprintf(stderr, "Could not initialise talloc context.\n");
881 return -1;
884 if (!c->opt_kerberos) {
885 use_in_memory_ccache();
888 werr = libnet_init_UnjoinCtx(ctx, &r);
889 if (!W_ERROR_IS_OK(werr)) {
890 d_fprintf(stderr, "Could not initialise unjoin context.\n");
891 return -1;
894 r->in.debug = true;
895 r->in.use_kerberos = c->opt_kerberos;
896 r->in.dc_name = c->opt_host;
897 r->in.domain_name = lp_realm();
898 r->in.admin_account = c->opt_user_name;
899 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
900 r->in.modify_config = lp_config_backend_is_registry();
901 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
902 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
904 werr = libnet_Unjoin(ctx, r);
905 if (!W_ERROR_IS_OK(werr)) {
906 d_printf("Failed to leave domain: %s\n",
907 r->out.error_string ? r->out.error_string :
908 get_friendly_werror_msg(werr));
909 goto done;
912 if (W_ERROR_IS_OK(werr)) {
913 d_printf("Deleted account for '%s' in realm '%s'\n",
914 r->in.machine_name, r->out.dns_domain_name);
915 goto done;
918 /* We couldn't delete it - see if the disable succeeded. */
919 if (r->out.disabled_machine_account) {
920 d_printf("Disabled account for '%s' in realm '%s'\n",
921 r->in.machine_name, r->out.dns_domain_name);
922 werr = WERR_OK;
923 goto done;
926 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
927 r->in.machine_name, r->out.dns_domain_name);
929 done:
930 TALLOC_FREE(r);
931 TALLOC_FREE(ctx);
933 if (W_ERROR_IS_OK(werr)) {
934 return 0;
937 return -1;
940 static NTSTATUS net_ads_join_ok(struct net_context *c)
942 ADS_STRUCT *ads = NULL;
943 ADS_STATUS status;
945 if (!secrets_init()) {
946 DEBUG(1,("Failed to initialise secrets database\n"));
947 return NT_STATUS_ACCESS_DENIED;
950 net_use_krb_machine_account(c);
952 status = ads_startup(c, true, &ads);
953 if (!ADS_ERR_OK(status)) {
954 return ads_ntstatus(status);
957 ads_destroy(&ads);
958 return NT_STATUS_OK;
962 check that an existing join is OK
964 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
966 NTSTATUS status;
967 use_in_memory_ccache();
969 if (c->display_usage) {
970 d_printf("Usage:\n"
971 "net ads testjoin\n"
972 " Test if the existing join is ok\n");
973 return 0;
976 /* Display success or failure */
977 status = net_ads_join_ok(c);
978 if (!NT_STATUS_IS_OK(status)) {
979 fprintf(stderr,"Join to domain is not valid: %s\n",
980 get_friendly_nt_error_msg(status));
981 return -1;
984 printf("Join is OK\n");
985 return 0;
988 /*******************************************************************
989 Simple configu checks before beginning the join
990 ********************************************************************/
992 static WERROR check_ads_config( void )
994 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
995 d_printf("Host is not configured as a member server.\n");
996 return WERR_INVALID_DOMAIN_ROLE;
999 if (strlen(global_myname()) > 15) {
1000 d_printf("Our netbios name can be at most 15 chars long, "
1001 "\"%s\" is %u chars long\n", global_myname(),
1002 (unsigned int)strlen(global_myname()));
1003 return WERR_INVALID_COMPUTERNAME;
1006 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1007 d_fprintf(stderr, "realm must be set in in %s for ADS "
1008 "join to succeed.\n", get_dyn_CONFIGFILE());
1009 return WERR_INVALID_PARAM;
1012 return WERR_OK;
1015 /*******************************************************************
1016 Send a DNS update request
1017 *******************************************************************/
1019 #if defined(WITH_DNS_UPDATES)
1020 #include "dns.h"
1021 DNS_ERROR DoDNSUpdate(char *pszServerName,
1022 const char *pszDomainName, const char *pszHostName,
1023 const struct sockaddr_storage *sslist,
1024 size_t num_addrs );
1026 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1027 const char *machine_name,
1028 const struct sockaddr_storage *addrs,
1029 int num_addrs)
1031 struct dns_rr_ns *nameservers = NULL;
1032 int ns_count = 0;
1033 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1034 DNS_ERROR dns_err;
1035 fstring dns_server;
1036 const char *dnsdomain = NULL;
1037 char *root_domain = NULL;
1039 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1040 d_printf("No DNS domain configured for %s. "
1041 "Unable to perform DNS Update.\n", machine_name);
1042 status = NT_STATUS_INVALID_PARAMETER;
1043 goto done;
1045 dnsdomain++;
1047 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1048 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1049 /* Child domains often do not have NS records. Look
1050 for the NS record for the forest root domain
1051 (rootDomainNamingContext in therootDSE) */
1053 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1054 LDAPMessage *msg = NULL;
1055 char *root_dn;
1056 ADS_STATUS ads_status;
1058 if ( !ads->ldap.ld ) {
1059 ads_status = ads_connect( ads );
1060 if ( !ADS_ERR_OK(ads_status) ) {
1061 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1062 goto done;
1066 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1067 "(objectclass=*)", rootname_attrs, &msg);
1068 if (!ADS_ERR_OK(ads_status)) {
1069 goto done;
1072 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1073 if ( !root_dn ) {
1074 ads_msgfree( ads, msg );
1075 goto done;
1078 root_domain = ads_build_domain( root_dn );
1080 /* cleanup */
1081 ads_msgfree( ads, msg );
1083 /* try again for NS servers */
1085 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1087 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1088 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1089 "realm\n", ads->config.realm));
1090 goto done;
1093 dnsdomain = root_domain;
1097 /* Now perform the dns update - we'll try non-secure and if we fail,
1098 we'll follow it up with a secure update */
1100 fstrcpy( dns_server, nameservers[0].hostname );
1102 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1103 if (!ERR_DNS_IS_OK(dns_err)) {
1104 status = NT_STATUS_UNSUCCESSFUL;
1107 done:
1109 SAFE_FREE( root_domain );
1111 return status;
1114 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1116 int num_addrs;
1117 struct sockaddr_storage *iplist = NULL;
1118 fstring machine_name;
1119 NTSTATUS status;
1121 name_to_fqdn( machine_name, global_myname() );
1122 strlower_m( machine_name );
1124 /* Get our ip address (not the 127.0.0.x address but a real ip
1125 * address) */
1127 num_addrs = get_my_ip_address( &iplist );
1128 if ( num_addrs <= 0 ) {
1129 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1130 "addresses!\n"));
1131 return NT_STATUS_INVALID_PARAMETER;
1134 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1135 iplist, num_addrs);
1136 SAFE_FREE( iplist );
1137 return status;
1139 #endif
1142 /*******************************************************************
1143 ********************************************************************/
1145 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1147 d_printf("net ads join [options]\n");
1148 d_printf("Valid options:\n");
1149 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1150 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1151 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1152 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1153 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1154 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1155 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1156 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1157 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1158 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1159 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1160 d_printf(" the two other attributes.\n");
1162 return -1;
1165 /*******************************************************************
1166 ********************************************************************/
1168 int net_ads_join(struct net_context *c, int argc, const char **argv)
1170 TALLOC_CTX *ctx = NULL;
1171 struct libnet_JoinCtx *r = NULL;
1172 const char *domain = lp_realm();
1173 WERROR werr = WERR_SETUP_NOT_JOINED;
1174 bool createupn = false;
1175 const char *machineupn = NULL;
1176 const char *create_in_ou = NULL;
1177 int i;
1178 const char *os_name = NULL;
1179 const char *os_version = NULL;
1180 bool modify_config = lp_config_backend_is_registry();
1182 if (c->display_usage)
1183 return net_ads_join_usage(c, argc, argv);
1185 if (!modify_config) {
1187 werr = check_ads_config();
1188 if (!W_ERROR_IS_OK(werr)) {
1189 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1190 goto fail;
1194 if (!(ctx = talloc_init("net_ads_join"))) {
1195 d_fprintf(stderr, "Could not initialise talloc context.\n");
1196 werr = WERR_NOMEM;
1197 goto fail;
1200 if (!c->opt_kerberos) {
1201 use_in_memory_ccache();
1204 werr = libnet_init_JoinCtx(ctx, &r);
1205 if (!W_ERROR_IS_OK(werr)) {
1206 goto fail;
1209 /* process additional command line args */
1211 for ( i=0; i<argc; i++ ) {
1212 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1213 createupn = true;
1214 machineupn = get_string_param(argv[i]);
1216 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1217 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1218 d_fprintf(stderr, "Please supply a valid OU path.\n");
1219 werr = WERR_INVALID_PARAM;
1220 goto fail;
1223 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1224 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1225 d_fprintf(stderr, "Please supply a operating system name.\n");
1226 werr = WERR_INVALID_PARAM;
1227 goto fail;
1230 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1231 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1232 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1233 werr = WERR_INVALID_PARAM;
1234 goto fail;
1237 else {
1238 domain = argv[i];
1242 if (!*domain) {
1243 d_fprintf(stderr, "Please supply a valid domain name\n");
1244 werr = WERR_INVALID_PARAM;
1245 goto fail;
1248 /* Do the domain join here */
1250 r->in.domain_name = domain;
1251 r->in.create_upn = createupn;
1252 r->in.upn = machineupn;
1253 r->in.account_ou = create_in_ou;
1254 r->in.os_name = os_name;
1255 r->in.os_version = os_version;
1256 r->in.dc_name = c->opt_host;
1257 r->in.admin_account = c->opt_user_name;
1258 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1259 r->in.debug = true;
1260 r->in.use_kerberos = c->opt_kerberos;
1261 r->in.modify_config = modify_config;
1262 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1263 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1264 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1266 werr = libnet_Join(ctx, r);
1267 if (!W_ERROR_IS_OK(werr)) {
1268 goto fail;
1271 /* Check the short name of the domain */
1273 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1274 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1275 d_printf("domain name obtained from the server.\n");
1276 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1277 d_printf("You should set \"workgroup = %s\" in %s.\n",
1278 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1281 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1283 if (r->out.dns_domain_name) {
1284 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1285 r->out.dns_domain_name);
1286 } else {
1287 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1288 r->out.netbios_domain_name);
1291 #if defined(WITH_DNS_UPDATES)
1292 if (r->out.domain_is_ad) {
1293 /* We enter this block with user creds */
1294 ADS_STRUCT *ads_dns = NULL;
1296 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1297 /* kinit with the machine password */
1299 use_in_memory_ccache();
1300 asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1301 ads_dns->auth.password = secrets_fetch_machine_password(
1302 r->out.netbios_domain_name, NULL, NULL );
1303 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1304 strupper_m(ads_dns->auth.realm );
1305 ads_kinit_password( ads_dns );
1308 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1309 d_fprintf( stderr, "DNS update failed!\n" );
1312 /* exit from this block using machine creds */
1313 ads_destroy(&ads_dns);
1315 #endif
1316 TALLOC_FREE(r);
1317 TALLOC_FREE( ctx );
1319 return 0;
1321 fail:
1322 /* issue an overall failure message at the end. */
1323 d_printf("Failed to join domain: %s\n",
1324 r && r->out.error_string ? r->out.error_string :
1325 get_friendly_werror_msg(werr));
1326 TALLOC_FREE( ctx );
1328 return -1;
1331 /*******************************************************************
1332 ********************************************************************/
1334 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1336 #if defined(WITH_DNS_UPDATES)
1337 ADS_STRUCT *ads;
1338 ADS_STATUS status;
1339 TALLOC_CTX *ctx;
1341 #ifdef DEVELOPER
1342 talloc_enable_leak_report();
1343 #endif
1345 if (argc > 0 || c->display_usage) {
1346 d_printf("Usage:\n"
1347 "net ads dns register\n"
1348 " Register hostname with DNS\n");
1349 return -1;
1352 if (!(ctx = talloc_init("net_ads_dns"))) {
1353 d_fprintf(stderr, "Could not initialise talloc context\n");
1354 return -1;
1357 status = ads_startup(c, true, &ads);
1358 if ( !ADS_ERR_OK(status) ) {
1359 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1360 TALLOC_FREE(ctx);
1361 return -1;
1364 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1365 d_fprintf( stderr, "DNS update failed!\n" );
1366 ads_destroy( &ads );
1367 TALLOC_FREE( ctx );
1368 return -1;
1371 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1373 ads_destroy(&ads);
1374 TALLOC_FREE( ctx );
1376 return 0;
1377 #else
1378 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1379 return -1;
1380 #endif
1383 #if defined(WITH_DNS_UPDATES)
1384 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1385 #endif
1387 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1389 #if defined(WITH_DNS_UPDATES)
1390 DNS_ERROR err;
1392 #ifdef DEVELOPER
1393 talloc_enable_leak_report();
1394 #endif
1396 if (argc != 2 || c->display_usage) {
1397 d_printf("Usage:\n"
1398 "net ads dns gethostbyname <server> <name>\n"
1399 " Look up hostname from the AD\n"
1400 " server\tName server to use\n"
1401 " name\tName to look up\n");
1402 return -1;
1405 err = do_gethostbyname(argv[0], argv[1]);
1407 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1408 #endif
1409 return 0;
1412 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1414 struct functable func[] = {
1416 "register",
1417 net_ads_dns_register,
1418 NET_TRANSPORT_ADS,
1419 "Add host dns entry to AD",
1420 "net ads dns register\n"
1421 " Add host dns entry to AD"
1424 "gethostbyname",
1425 net_ads_dns_gethostbyname,
1426 NET_TRANSPORT_ADS,
1427 "Look up host",
1428 "net ads dns gethostbyname\n"
1429 " Look up host"
1431 {NULL, NULL, 0, NULL, NULL}
1434 return net_run_function(c, argc, argv, "net ads dns", func);
1437 /*******************************************************************
1438 ********************************************************************/
1440 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1442 d_printf(
1443 "\nnet ads printer search <printer>"
1444 "\n\tsearch for a printer in the directory\n"
1445 "\nnet ads printer info <printer> <server>"
1446 "\n\tlookup info in directory for printer on server"
1447 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1448 "\nnet ads printer publish <printername>"
1449 "\n\tpublish printer in directory"
1450 "\n\t(note: printer name is required)\n"
1451 "\nnet ads printer remove <printername>"
1452 "\n\tremove printer from directory"
1453 "\n\t(note: printer name is required)\n");
1454 return -1;
1457 /*******************************************************************
1458 ********************************************************************/
1460 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1462 ADS_STRUCT *ads;
1463 ADS_STATUS rc;
1464 LDAPMessage *res = NULL;
1466 if (c->display_usage) {
1467 d_printf("Usage:\n"
1468 "net ads printer search\n"
1469 " List printers in the AD\n");
1470 return 0;
1473 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1474 return -1;
1477 rc = ads_find_printers(ads, &res);
1479 if (!ADS_ERR_OK(rc)) {
1480 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1481 ads_msgfree(ads, res);
1482 ads_destroy(&ads);
1483 return -1;
1486 if (ads_count_replies(ads, res) == 0) {
1487 d_fprintf(stderr, "No results found\n");
1488 ads_msgfree(ads, res);
1489 ads_destroy(&ads);
1490 return -1;
1493 ads_dump(ads, res);
1494 ads_msgfree(ads, res);
1495 ads_destroy(&ads);
1496 return 0;
1499 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1501 ADS_STRUCT *ads;
1502 ADS_STATUS rc;
1503 const char *servername, *printername;
1504 LDAPMessage *res = NULL;
1506 if (c->display_usage) {
1507 d_printf("Usage:\n"
1508 "net ads printer info [printername [servername]]\n"
1509 " Display printer info from AD\n"
1510 " printername\tPrinter name or wildcard\n"
1511 " servername\tName of the print server\n");
1512 return 0;
1515 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1516 return -1;
1519 if (argc > 0) {
1520 printername = argv[0];
1521 } else {
1522 printername = "*";
1525 if (argc > 1) {
1526 servername = argv[1];
1527 } else {
1528 servername = global_myname();
1531 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1533 if (!ADS_ERR_OK(rc)) {
1534 d_fprintf(stderr, "Server '%s' not found: %s\n",
1535 servername, ads_errstr(rc));
1536 ads_msgfree(ads, res);
1537 ads_destroy(&ads);
1538 return -1;
1541 if (ads_count_replies(ads, res) == 0) {
1542 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1543 ads_msgfree(ads, res);
1544 ads_destroy(&ads);
1545 return -1;
1548 ads_dump(ads, res);
1549 ads_msgfree(ads, res);
1550 ads_destroy(&ads);
1552 return 0;
1555 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1557 ADS_STRUCT *ads;
1558 ADS_STATUS rc;
1559 const char *servername, *printername;
1560 struct cli_state *cli;
1561 struct rpc_pipe_client *pipe_hnd;
1562 struct sockaddr_storage server_ss;
1563 NTSTATUS nt_status;
1564 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1565 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1566 char *prt_dn, *srv_dn, **srv_cn;
1567 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1568 LDAPMessage *res = NULL;
1570 if (argc < 1 || c->display_usage) {
1571 d_printf("Usage:\n"
1572 "net ads printer publish <printername> [servername]\n"
1573 " Publish printer in AD\n"
1574 " printername\tName of the printer\n"
1575 " servername\tName of the print server\n");
1576 talloc_destroy(mem_ctx);
1577 return -1;
1580 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1581 talloc_destroy(mem_ctx);
1582 return -1;
1585 printername = argv[0];
1587 if (argc == 2) {
1588 servername = argv[1];
1589 } else {
1590 servername = global_myname();
1593 /* Get printer data from SPOOLSS */
1595 resolve_name(servername, &server_ss, 0x20);
1597 nt_status = cli_full_connection(&cli, global_myname(), servername,
1598 &server_ss, 0,
1599 "IPC$", "IPC",
1600 c->opt_user_name, c->opt_workgroup,
1601 c->opt_password ? c->opt_password : "",
1602 CLI_FULL_CONNECTION_USE_KERBEROS,
1603 Undefined, NULL);
1605 if (NT_STATUS_IS_ERR(nt_status)) {
1606 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1607 "for %s\n", servername, printername);
1608 ads_destroy(&ads);
1609 talloc_destroy(mem_ctx);
1610 return -1;
1613 /* Publish on AD server */
1615 ads_find_machine_acct(ads, &res, servername);
1617 if (ads_count_replies(ads, res) == 0) {
1618 d_fprintf(stderr, "Could not find machine account for server %s\n",
1619 servername);
1620 ads_destroy(&ads);
1621 talloc_destroy(mem_ctx);
1622 return -1;
1625 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1626 srv_cn = ldap_explode_dn(srv_dn, 1);
1628 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1629 printername_escaped = escape_rdn_val_string_alloc(printername);
1630 if (!srv_cn_escaped || !printername_escaped) {
1631 SAFE_FREE(srv_cn_escaped);
1632 SAFE_FREE(printername_escaped);
1633 d_fprintf(stderr, "Internal error, out of memory!");
1634 ads_destroy(&ads);
1635 talloc_destroy(mem_ctx);
1636 return -1;
1639 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1641 SAFE_FREE(srv_cn_escaped);
1642 SAFE_FREE(printername_escaped);
1644 nt_status = cli_rpc_pipe_open_noauth(cli, &syntax_spoolss, &pipe_hnd);
1645 if (!NT_STATUS_IS_OK(nt_status)) {
1646 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1647 servername);
1648 SAFE_FREE(prt_dn);
1649 ads_destroy(&ads);
1650 talloc_destroy(mem_ctx);
1651 return -1;
1654 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1655 printername))) {
1656 SAFE_FREE(prt_dn);
1657 ads_destroy(&ads);
1658 talloc_destroy(mem_ctx);
1659 return -1;
1662 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1663 if (!ADS_ERR_OK(rc)) {
1664 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1665 SAFE_FREE(prt_dn);
1666 ads_destroy(&ads);
1667 talloc_destroy(mem_ctx);
1668 return -1;
1671 d_printf("published printer\n");
1672 SAFE_FREE(prt_dn);
1673 ads_destroy(&ads);
1674 talloc_destroy(mem_ctx);
1676 return 0;
1679 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1681 ADS_STRUCT *ads;
1682 ADS_STATUS rc;
1683 const char *servername;
1684 char *prt_dn;
1685 LDAPMessage *res = NULL;
1687 if (argc < 1 || c->display_usage) {
1688 d_printf("Usage:\n"
1689 "net ads printer remove <printername> [servername]\n"
1690 " Remove a printer from the AD\n"
1691 " printername\tName of the printer\n"
1692 " servername\tName of the print server\n");
1693 return -1;
1696 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1697 return -1;
1700 if (argc > 1) {
1701 servername = argv[1];
1702 } else {
1703 servername = global_myname();
1706 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1708 if (!ADS_ERR_OK(rc)) {
1709 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1710 ads_msgfree(ads, res);
1711 ads_destroy(&ads);
1712 return -1;
1715 if (ads_count_replies(ads, res) == 0) {
1716 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1717 ads_msgfree(ads, res);
1718 ads_destroy(&ads);
1719 return -1;
1722 prt_dn = ads_get_dn(ads, res);
1723 ads_msgfree(ads, res);
1724 rc = ads_del_dn(ads, prt_dn);
1725 ads_memfree(ads, prt_dn);
1727 if (!ADS_ERR_OK(rc)) {
1728 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1729 ads_destroy(&ads);
1730 return -1;
1733 ads_destroy(&ads);
1734 return 0;
1737 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1739 struct functable func[] = {
1741 "search",
1742 net_ads_printer_search,
1743 NET_TRANSPORT_ADS,
1744 "Search for a printer",
1745 "net ads printer search\n"
1746 " Search for a printer"
1749 "info",
1750 net_ads_printer_info,
1751 NET_TRANSPORT_ADS,
1752 "Display printer information",
1753 "net ads printer info\n"
1754 " Display printer information"
1757 "publish",
1758 net_ads_printer_publish,
1759 NET_TRANSPORT_ADS,
1760 "Publish a printer",
1761 "net ads printer publish\n"
1762 " Publish a printer"
1765 "remove",
1766 net_ads_printer_remove,
1767 NET_TRANSPORT_ADS,
1768 "Delete a printer",
1769 "net ads printer remove\n"
1770 " Delete a printer"
1772 {NULL, NULL, 0, NULL, NULL}
1775 return net_run_function(c, argc, argv, "net ads printer", func);
1779 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1781 ADS_STRUCT *ads;
1782 const char *auth_principal = c->opt_user_name;
1783 const char *auth_password = c->opt_password;
1784 char *realm = NULL;
1785 char *new_password = NULL;
1786 char *chr, *prompt;
1787 const char *user;
1788 ADS_STATUS ret;
1790 if (c->display_usage) {
1791 d_printf("Usage:\n"
1792 "net ads password <username>\n"
1793 " Change password for user\n"
1794 " username\tName of user to change password for\n");
1795 return 0;
1798 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1799 d_fprintf(stderr, "You must supply an administrator username/password\n");
1800 return -1;
1803 if (argc < 1) {
1804 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1805 return -1;
1808 user = argv[0];
1809 if (!strchr_m(user, '@')) {
1810 asprintf(&chr, "%s@%s", argv[0], lp_realm());
1811 user = chr;
1814 use_in_memory_ccache();
1815 chr = strchr_m(auth_principal, '@');
1816 if (chr) {
1817 realm = ++chr;
1818 } else {
1819 realm = lp_realm();
1822 /* use the realm so we can eventually change passwords for users
1823 in realms other than default */
1824 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1825 return -1;
1828 /* we don't actually need a full connect, but it's the easy way to
1829 fill in the KDC's addresss */
1830 ads_connect(ads);
1832 if (!ads->config.realm) {
1833 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1834 return -1;
1837 if (argv[1]) {
1838 new_password = (char *)argv[1];
1839 } else {
1840 asprintf(&prompt, "Enter new password for %s:", user);
1841 new_password = getpass(prompt);
1842 free(prompt);
1845 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1846 auth_password, user, new_password, ads->auth.time_offset);
1847 if (!ADS_ERR_OK(ret)) {
1848 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1849 ads_destroy(&ads);
1850 return -1;
1853 d_printf("Password change for %s completed.\n", user);
1854 ads_destroy(&ads);
1856 return 0;
1859 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1861 ADS_STRUCT *ads;
1862 char *host_principal;
1863 fstring my_name;
1864 ADS_STATUS ret;
1866 if (c->display_usage) {
1867 d_printf("Usage:\n"
1868 "net ads changetrustpw\n"
1869 " Change the machine account's trust password\n");
1870 return 0;
1873 if (!secrets_init()) {
1874 DEBUG(1,("Failed to initialise secrets database\n"));
1875 return -1;
1878 net_use_krb_machine_account(c);
1880 use_in_memory_ccache();
1882 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1883 return -1;
1886 fstrcpy(my_name, global_myname());
1887 strlower_m(my_name);
1888 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1889 d_printf("Changing password for principal: %s\n", host_principal);
1891 ret = ads_change_trust_account_password(ads, host_principal);
1893 if (!ADS_ERR_OK(ret)) {
1894 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1895 ads_destroy(&ads);
1896 SAFE_FREE(host_principal);
1897 return -1;
1900 d_printf("Password change for principal %s succeeded.\n", host_principal);
1902 if (lp_use_kerberos_keytab()) {
1903 d_printf("Attempting to update system keytab with new password.\n");
1904 if (ads_keytab_create_default(ads)) {
1905 d_printf("Failed to update system keytab.\n");
1909 ads_destroy(&ads);
1910 SAFE_FREE(host_principal);
1912 return 0;
1916 help for net ads search
1918 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
1920 d_printf(
1921 "\nnet ads search <expression> <attributes...>\n"
1922 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1923 "The expression is a standard LDAP search expression, and the\n"
1924 "attributes are a list of LDAP fields to show in the results.\n\n"
1925 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1927 net_common_flags_usage(c, argc, argv);
1928 return -1;
1933 general ADS search function. Useful in diagnosing problems in ADS
1935 static int net_ads_search(struct net_context *c, int argc, const char **argv)
1937 ADS_STRUCT *ads;
1938 ADS_STATUS rc;
1939 const char *ldap_exp;
1940 const char **attrs;
1941 LDAPMessage *res = NULL;
1943 if (argc < 1 || c->display_usage) {
1944 return net_ads_search_usage(c, argc, argv);
1947 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1948 return -1;
1951 ldap_exp = argv[0];
1952 attrs = (argv + 1);
1954 rc = ads_do_search_all(ads, ads->config.bind_path,
1955 LDAP_SCOPE_SUBTREE,
1956 ldap_exp, attrs, &res);
1957 if (!ADS_ERR_OK(rc)) {
1958 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1959 ads_destroy(&ads);
1960 return -1;
1963 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1965 /* dump the results */
1966 ads_dump(ads, res);
1968 ads_msgfree(ads, res);
1969 ads_destroy(&ads);
1971 return 0;
1976 help for net ads search
1978 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
1980 d_printf(
1981 "\nnet ads dn <dn> <attributes...>\n"
1982 "\nperform a raw LDAP search on a ADS server and dump the results\n"
1983 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
1984 "to show in the results\n\n"
1985 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1986 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1988 net_common_flags_usage(c, argc, argv);
1989 return -1;
1994 general ADS search function. Useful in diagnosing problems in ADS
1996 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
1998 ADS_STRUCT *ads;
1999 ADS_STATUS rc;
2000 const char *dn;
2001 const char **attrs;
2002 LDAPMessage *res = NULL;
2004 if (argc < 1 || c->display_usage) {
2005 return net_ads_dn_usage(c, argc, argv);
2008 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2009 return -1;
2012 dn = argv[0];
2013 attrs = (argv + 1);
2015 rc = ads_do_search_all(ads, dn,
2016 LDAP_SCOPE_BASE,
2017 "(objectclass=*)", attrs, &res);
2018 if (!ADS_ERR_OK(rc)) {
2019 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2020 ads_destroy(&ads);
2021 return -1;
2024 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2026 /* dump the results */
2027 ads_dump(ads, res);
2029 ads_msgfree(ads, res);
2030 ads_destroy(&ads);
2032 return 0;
2036 help for net ads sid search
2038 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2040 d_printf(
2041 "\nnet ads sid <sid> <attributes...>\n"
2042 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2043 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2044 "to show in the results\n\n"
2045 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2047 net_common_flags_usage(c, argc, argv);
2048 return -1;
2053 general ADS search function. Useful in diagnosing problems in ADS
2055 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2057 ADS_STRUCT *ads;
2058 ADS_STATUS rc;
2059 const char *sid_string;
2060 const char **attrs;
2061 LDAPMessage *res = NULL;
2062 DOM_SID sid;
2064 if (argc < 1 || c->display_usage) {
2065 return net_ads_sid_usage(c, argc, argv);
2068 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2069 return -1;
2072 sid_string = argv[0];
2073 attrs = (argv + 1);
2075 if (!string_to_sid(&sid, sid_string)) {
2076 d_fprintf(stderr, "could not convert sid\n");
2077 ads_destroy(&ads);
2078 return -1;
2081 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2082 if (!ADS_ERR_OK(rc)) {
2083 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2084 ads_destroy(&ads);
2085 return -1;
2088 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2090 /* dump the results */
2091 ads_dump(ads, res);
2093 ads_msgfree(ads, res);
2094 ads_destroy(&ads);
2096 return 0;
2099 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2101 int ret;
2102 ADS_STRUCT *ads;
2104 if (c->display_usage) {
2105 d_printf("Usage:\n"
2106 "net ads keytab flush\n"
2107 " Delete the whole keytab\n");
2108 return 0;
2111 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2112 return -1;
2114 ret = ads_keytab_flush(ads);
2115 ads_destroy(&ads);
2116 return ret;
2119 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2121 int i;
2122 int ret = 0;
2123 ADS_STRUCT *ads;
2125 if (c->display_usage) {
2126 d_printf("Usage:\n"
2127 "net ads keytab add <principal> [principal ...]\n"
2128 " Add principals to local keytab\n"
2129 " principal\tKerberos principal to add to "
2130 "keytab\n");
2131 return 0;
2134 d_printf("Processing principals to add...\n");
2135 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2136 return -1;
2138 for (i = 0; i < argc; i++) {
2139 ret |= ads_keytab_add_entry(ads, argv[i]);
2141 ads_destroy(&ads);
2142 return ret;
2145 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2147 ADS_STRUCT *ads;
2148 int ret;
2150 if (c->display_usage) {
2151 d_printf("Usage:\n"
2152 "net ads keytab create\n"
2153 " Create new default keytab\n");
2154 return 0;
2157 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2158 return -1;
2160 ret = ads_keytab_create_default(ads);
2161 ads_destroy(&ads);
2162 return ret;
2165 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2167 const char *keytab = NULL;
2169 if (c->display_usage) {
2170 d_printf("Usage:\n"
2171 "net ads keytab list [keytab]\n"
2172 " List a local keytab\n"
2173 " keytab\tKeytab to list\n");
2174 return 0;
2177 if (argc >= 1) {
2178 keytab = argv[0];
2181 return ads_keytab_list(keytab);
2185 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2187 struct functable func[] = {
2189 "add",
2190 net_ads_keytab_add,
2191 NET_TRANSPORT_ADS,
2192 "Add a service principal",
2193 "net ads keytab add\n"
2194 " Add a service principal"
2197 "create",
2198 net_ads_keytab_create,
2199 NET_TRANSPORT_ADS,
2200 "Create a fresh keytab",
2201 "net ads keytab create\n"
2202 " Create a fresh keytab"
2205 "flush",
2206 net_ads_keytab_flush,
2207 NET_TRANSPORT_ADS,
2208 "Remove all keytab entries",
2209 "net ads keytab flush\n"
2210 " Remove all keytab entries"
2213 "list",
2214 net_ads_keytab_list,
2215 NET_TRANSPORT_ADS,
2216 "List a keytab",
2217 "net ads keytab list\n"
2218 " List a keytab"
2220 {NULL, NULL, 0, NULL, NULL}
2223 if (!lp_use_kerberos_keytab()) {
2224 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2225 use keytab functions.\n");
2228 return net_run_function(c, argc, argv, "net ads keytab", func);
2231 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2233 int ret = -1;
2235 if (c->display_usage) {
2236 d_printf("Usage:\n"
2237 "net ads kerberos renew\n"
2238 " Renew TGT from existing credential cache\n");
2239 return 0;
2242 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2243 if (ret) {
2244 d_printf("failed to renew kerberos ticket: %s\n",
2245 error_message(ret));
2247 return ret;
2250 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2252 struct PAC_DATA *pac = NULL;
2253 struct PAC_LOGON_INFO *info = NULL;
2254 TALLOC_CTX *mem_ctx = NULL;
2255 NTSTATUS status;
2256 int ret = -1;
2258 if (c->display_usage) {
2259 d_printf("Usage:\n"
2260 "net ads kerberos pac\n"
2261 " Dump the Kerberos PAC\n");
2262 return 0;
2265 mem_ctx = talloc_init("net_ads_kerberos_pac");
2266 if (!mem_ctx) {
2267 goto out;
2270 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2272 status = kerberos_return_pac(mem_ctx,
2273 c->opt_user_name,
2274 c->opt_password,
2276 NULL,
2277 NULL,
2278 NULL,
2279 true,
2280 true,
2281 2592000, /* one month */
2282 &pac);
2283 if (!NT_STATUS_IS_OK(status)) {
2284 d_printf("failed to query kerberos PAC: %s\n",
2285 nt_errstr(status));
2286 goto out;
2289 info = get_logon_info_from_pac(pac);
2290 if (info) {
2291 const char *s;
2292 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2293 d_printf("The Pac: %s\n", s);
2296 ret = 0;
2297 out:
2298 TALLOC_FREE(mem_ctx);
2299 return ret;
2302 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2304 TALLOC_CTX *mem_ctx = NULL;
2305 int ret = -1;
2306 NTSTATUS status;
2308 if (c->display_usage) {
2309 d_printf("Usage:\n"
2310 "net ads kerberos kinit\n"
2311 " Get Ticket Granting Ticket (TGT) for the user\n");
2312 return 0;
2315 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2316 if (!mem_ctx) {
2317 goto out;
2320 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2322 ret = kerberos_kinit_password_ext(c->opt_user_name,
2323 c->opt_password,
2325 NULL,
2326 NULL,
2327 NULL,
2328 true,
2329 true,
2330 2592000, /* one month */
2331 &status);
2332 if (ret) {
2333 d_printf("failed to kinit password: %s\n",
2334 nt_errstr(status));
2336 out:
2337 return ret;
2340 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2342 struct functable func[] = {
2344 "kinit",
2345 net_ads_kerberos_kinit,
2346 NET_TRANSPORT_ADS,
2347 "Retrieve Ticket Granting Ticket (TGT)",
2348 "net ads kerberos kinit\n"
2349 " Receive Ticket Granting Ticket (TGT)"
2352 "renew",
2353 net_ads_kerberos_renew,
2354 NET_TRANSPORT_ADS,
2355 "Renew Ticket Granting Ticket from credential cache"
2356 "net ads kerberos renew\n"
2357 " Renew Ticket Granting Ticket from credential cache"
2360 "pac",
2361 net_ads_kerberos_pac,
2362 NET_TRANSPORT_ADS,
2363 "Dump Kerberos PAC",
2364 "net ads kerberos pac\n"
2365 " Dump Kerberos PAC"
2367 {NULL, NULL, 0, NULL, NULL}
2370 return net_run_function(c, argc, argv, "net ads kerberos", func);
2373 int net_ads(struct net_context *c, int argc, const char **argv)
2375 struct functable func[] = {
2377 "info",
2378 net_ads_info,
2379 NET_TRANSPORT_ADS,
2380 "Display details on remote ADS server",
2381 "net ads info\n"
2382 " Display details on remote ADS server"
2385 "join",
2386 net_ads_join,
2387 NET_TRANSPORT_ADS,
2388 "Join the local machine to ADS realm",
2389 "net ads join\n"
2390 " Join the local machine to ADS realm"
2393 "testjoin",
2394 net_ads_testjoin,
2395 NET_TRANSPORT_ADS,
2396 "Validate machine account",
2397 "net ads testjoin\n"
2398 " Validate machine account"
2401 "leave",
2402 net_ads_leave,
2403 NET_TRANSPORT_ADS,
2404 "Remove the local machine from ADS",
2405 "net ads leave\n"
2406 " Remove the local machine from ADS"
2409 "status",
2410 net_ads_status,
2411 NET_TRANSPORT_ADS,
2412 "Display machine account details",
2413 "net ads status\n"
2414 " Display machine account details"
2417 "user",
2418 net_ads_user,
2419 NET_TRANSPORT_ADS,
2420 "List/modify users",
2421 "net ads user\n"
2422 " List/modify users"
2425 "group",
2426 net_ads_group,
2427 NET_TRANSPORT_ADS,
2428 "List/modify groups",
2429 "net ads group\n"
2430 " List/modify groups"
2433 "dns",
2434 net_ads_dns,
2435 NET_TRANSPORT_ADS,
2436 "Issue dynamic DNS update",
2437 "net ads dns\n"
2438 " Issue dynamic DNS update"
2441 "password",
2442 net_ads_password,
2443 NET_TRANSPORT_ADS,
2444 "Change user passwords",
2445 "net ads password\n"
2446 " Change user passwords"
2449 "changetrustpw",
2450 net_ads_changetrustpw,
2451 NET_TRANSPORT_ADS,
2452 "Change trust account password",
2453 "net ads changetrustpw\n"
2454 " Change trust account password"
2457 "printer",
2458 net_ads_printer,
2459 NET_TRANSPORT_ADS,
2460 "List/modify printer entries",
2461 "net ads printer\n"
2462 " List/modify printer entries"
2465 "search",
2466 net_ads_search,
2467 NET_TRANSPORT_ADS,
2468 "Issue LDAP search using filter",
2469 "net ads search\n"
2470 " Issue LDAP search using filter"
2473 "dn",
2474 net_ads_dn,
2475 NET_TRANSPORT_ADS,
2476 "Issue LDAP search by DN",
2477 "net ads dn\n"
2478 " Issue LDAP search by DN"
2481 "sid",
2482 net_ads_sid,
2483 NET_TRANSPORT_ADS,
2484 "Issue LDAP search by SID",
2485 "net ads sid\n"
2486 " Issue LDAP search by SID"
2489 "workgroup",
2490 net_ads_workgroup,
2491 NET_TRANSPORT_ADS,
2492 "Display workgroup name",
2493 "net ads workgroup\n"
2494 " Display the workgroup name"
2497 "lookup",
2498 net_ads_lookup,
2499 NET_TRANSPORT_ADS,
2500 "Perfom CLDAP query on DC",
2501 "net ads lookup\n"
2502 " Find the ADS DC using CLDAP lookups"
2505 "keytab",
2506 net_ads_keytab,
2507 NET_TRANSPORT_ADS,
2508 "Manage local keytab file",
2509 "net ads keytab\n"
2510 " Manage local keytab file"
2513 "gpo",
2514 net_ads_gpo,
2515 NET_TRANSPORT_ADS,
2516 "Manage group policy objects",
2517 "net ads gpo\n"
2518 " Manage group policy objects"
2521 "kerberos",
2522 net_ads_kerberos,
2523 NET_TRANSPORT_ADS,
2524 "Manage kerberos keytab",
2525 "net ads kerberos\n"
2526 " Manage kerberos keytab"
2528 {NULL, NULL, 0, NULL, NULL}
2531 return net_run_function(c, argc, argv, "net ads", func);
2534 #else
2536 static int net_ads_noads(void)
2538 d_fprintf(stderr, "ADS support not compiled in\n");
2539 return -1;
2542 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2544 return net_ads_noads();
2547 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2549 return net_ads_noads();
2552 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2554 return net_ads_noads();
2557 int net_ads_join(struct net_context *c, int argc, const char **argv)
2559 return net_ads_noads();
2562 int net_ads_user(struct net_context *c, int argc, const char **argv)
2564 return net_ads_noads();
2567 int net_ads_group(struct net_context *c, int argc, const char **argv)
2569 return net_ads_noads();
2572 /* this one shouldn't display a message */
2573 int net_ads_check(struct net_context *c)
2575 return -1;
2578 int net_ads_check_our_domain(struct net_context *c)
2580 return -1;
2583 int net_ads(struct net_context *c, int argc, const char **argv)
2585 return net_ads_noads();
2588 #endif /* WITH_ADS */