docs: Improve description of the share commands in man smb.conf.
[Samba/gebeck_regimport.git] / source3 / utils / net_ads.c
blob766f3216f0b9c200c9c0ce246d2f75a34dc21caa
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_closest_dc(ads)) {
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 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
482 goto done;
484 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
485 ads->auth.time_offset);
486 SAFE_FREE(upn);
487 if (ADS_ERR_OK(status)) {
488 d_printf("User %s added\n", argv[0]);
489 rc = 0;
490 goto done;
493 /* password didn't set, delete account */
494 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
495 argv[0], ads_errstr(status));
496 ads_msgfree(ads, res);
497 status=ads_find_user_acct(ads, &res, argv[0]);
498 if (ADS_ERR_OK(status)) {
499 userdn = ads_get_dn(ads, res);
500 ads_del_dn(ads, userdn);
501 ads_memfree(ads, userdn);
504 done:
505 if (res)
506 ads_msgfree(ads, res);
507 ads_destroy(&ads);
508 SAFE_FREE(ou_str);
509 return rc;
512 static int ads_user_info(struct net_context *c, int argc, const char **argv)
514 ADS_STRUCT *ads;
515 ADS_STATUS rc;
516 LDAPMessage *res;
517 const char *attrs[] = {"memberOf", NULL};
518 char *searchstring=NULL;
519 char **grouplist;
520 char *escaped_user;
522 if (argc < 1 || c->display_usage) {
523 return net_ads_user_usage(c, argc, argv);
526 escaped_user = escape_ldap_string_alloc(argv[0]);
528 if (!escaped_user) {
529 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
530 return -1;
533 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
534 SAFE_FREE(escaped_user);
535 return -1;
538 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
539 SAFE_FREE(escaped_user);
540 return -1;
542 rc = ads_search(ads, &res, searchstring, attrs);
543 SAFE_FREE(searchstring);
545 if (!ADS_ERR_OK(rc)) {
546 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
547 ads_destroy(&ads);
548 SAFE_FREE(escaped_user);
549 return -1;
552 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
553 (LDAPMessage *)res, "memberOf");
555 if (grouplist) {
556 int i;
557 char **groupname;
558 for (i=0;grouplist[i];i++) {
559 groupname = ldap_explode_dn(grouplist[i], 1);
560 d_printf("%s\n", groupname[0]);
561 ldap_value_free(groupname);
563 ldap_value_free(grouplist);
566 ads_msgfree(ads, res);
567 ads_destroy(&ads);
568 SAFE_FREE(escaped_user);
569 return 0;
572 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
574 ADS_STRUCT *ads;
575 ADS_STATUS rc;
576 LDAPMessage *res = NULL;
577 char *userdn;
579 if (argc < 1) {
580 return net_ads_user_usage(c, argc, argv);
583 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
584 return -1;
587 rc = ads_find_user_acct(ads, &res, argv[0]);
588 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
589 d_printf("User %s does not exist.\n", argv[0]);
590 ads_msgfree(ads, res);
591 ads_destroy(&ads);
592 return -1;
594 userdn = ads_get_dn(ads, res);
595 ads_msgfree(ads, res);
596 rc = ads_del_dn(ads, userdn);
597 ads_memfree(ads, userdn);
598 if (ADS_ERR_OK(rc)) {
599 d_printf("User %s deleted\n", argv[0]);
600 ads_destroy(&ads);
601 return 0;
603 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
604 ads_errstr(rc));
605 ads_destroy(&ads);
606 return -1;
609 int net_ads_user(struct net_context *c, int argc, const char **argv)
611 struct functable func[] = {
613 "add",
614 ads_user_add,
615 NET_TRANSPORT_ADS,
616 "Add an AD user",
617 "net ads user add\n"
618 " Add an AD user"
621 "info",
622 ads_user_info,
623 NET_TRANSPORT_ADS,
624 "Display information about an AD user",
625 "net ads user info\n"
626 " Display information about an AD user"
629 "delete",
630 ads_user_delete,
631 NET_TRANSPORT_ADS,
632 "Delete an AD user",
633 "net ads user delete\n"
634 " Delete an AD user"
636 {NULL, NULL, 0, NULL, NULL}
638 ADS_STRUCT *ads;
639 ADS_STATUS rc;
640 const char *shortattrs[] = {"sAMAccountName", NULL};
641 const char *longattrs[] = {"sAMAccountName", "description", NULL};
642 char *disp_fields[2] = {NULL, NULL};
644 if (argc == 0) {
645 if (c->display_usage) {
646 d_printf("Usage:\n");
647 d_printf("net ads user\n"
648 " List AD users\n");
649 net_display_usage_from_functable(func);
650 return 0;
653 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
654 return -1;
657 if (c->opt_long_list_entries)
658 d_printf("\nUser name Comment"
659 "\n-----------------------------\n");
661 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
662 LDAP_SCOPE_SUBTREE,
663 "(objectCategory=user)",
664 c->opt_long_list_entries ? longattrs :
665 shortattrs, usergrp_display,
666 disp_fields);
667 ads_destroy(&ads);
668 return ADS_ERR_OK(rc) ? 0 : -1;
671 return net_run_function(c, argc, argv, "net ads user", func);
674 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
676 return net_group_usage(c, argc, argv);
679 static int ads_group_add(struct net_context *c, int argc, const char **argv)
681 ADS_STRUCT *ads;
682 ADS_STATUS status;
683 LDAPMessage *res=NULL;
684 int rc = -1;
685 char *ou_str = NULL;
687 if (argc < 1 || c->display_usage) {
688 return net_ads_group_usage(c, argc, argv);
691 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
692 return -1;
695 status = ads_find_user_acct(ads, &res, argv[0]);
697 if (!ADS_ERR_OK(status)) {
698 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
699 goto done;
702 if (ads_count_replies(ads, res)) {
703 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
704 goto done;
707 if (c->opt_container) {
708 ou_str = SMB_STRDUP(c->opt_container);
709 } else {
710 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
713 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
715 if (ADS_ERR_OK(status)) {
716 d_printf("Group %s added\n", argv[0]);
717 rc = 0;
718 } else {
719 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
720 ads_errstr(status));
723 done:
724 if (res)
725 ads_msgfree(ads, res);
726 ads_destroy(&ads);
727 SAFE_FREE(ou_str);
728 return rc;
731 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
733 ADS_STRUCT *ads;
734 ADS_STATUS rc;
735 LDAPMessage *res = NULL;
736 char *groupdn;
738 if (argc < 1 || c->display_usage) {
739 return net_ads_group_usage(c, argc, argv);
742 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
743 return -1;
746 rc = ads_find_user_acct(ads, &res, argv[0]);
747 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
748 d_printf("Group %s does not exist.\n", argv[0]);
749 ads_msgfree(ads, res);
750 ads_destroy(&ads);
751 return -1;
753 groupdn = ads_get_dn(ads, res);
754 ads_msgfree(ads, res);
755 rc = ads_del_dn(ads, groupdn);
756 ads_memfree(ads, groupdn);
757 if (ADS_ERR_OK(rc)) {
758 d_printf("Group %s deleted\n", argv[0]);
759 ads_destroy(&ads);
760 return 0;
762 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
763 ads_errstr(rc));
764 ads_destroy(&ads);
765 return -1;
768 int net_ads_group(struct net_context *c, int argc, const char **argv)
770 struct functable func[] = {
772 "add",
773 ads_group_add,
774 NET_TRANSPORT_ADS,
775 "Add an AD group",
776 "net ads group add\n"
777 " Add an AD group"
780 "delete",
781 ads_group_delete,
782 NET_TRANSPORT_ADS,
783 "Delete an AD group",
784 "net ads group delete\n"
785 " Delete an AD group"
787 {NULL, NULL, 0, NULL, NULL}
789 ADS_STRUCT *ads;
790 ADS_STATUS rc;
791 const char *shortattrs[] = {"sAMAccountName", NULL};
792 const char *longattrs[] = {"sAMAccountName", "description", NULL};
793 char *disp_fields[2] = {NULL, NULL};
795 if (argc == 0) {
796 if (c->display_usage) {
797 d_printf("Usage:\n");
798 d_printf("net ads group\n"
799 " List AD groups\n");
800 net_display_usage_from_functable(func);
801 return 0;
804 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
805 return -1;
808 if (c->opt_long_list_entries)
809 d_printf("\nGroup name Comment"
810 "\n-----------------------------\n");
811 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
812 LDAP_SCOPE_SUBTREE,
813 "(objectCategory=group)",
814 c->opt_long_list_entries ? longattrs :
815 shortattrs, usergrp_display,
816 disp_fields);
818 ads_destroy(&ads);
819 return ADS_ERR_OK(rc) ? 0 : -1;
821 return net_run_function(c, argc, argv, "net ads group", func);
824 static int net_ads_status(struct net_context *c, int argc, const char **argv)
826 ADS_STRUCT *ads;
827 ADS_STATUS rc;
828 LDAPMessage *res;
830 if (c->display_usage) {
831 d_printf("Usage:\n"
832 "net ads status\n"
833 " Display machine account details\n");
834 return 0;
837 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
838 return -1;
841 rc = ads_find_machine_acct(ads, &res, global_myname());
842 if (!ADS_ERR_OK(rc)) {
843 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
844 ads_destroy(&ads);
845 return -1;
848 if (ads_count_replies(ads, res) == 0) {
849 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
850 ads_destroy(&ads);
851 return -1;
854 ads_dump(ads, res);
855 ads_destroy(&ads);
856 return 0;
859 /*******************************************************************
860 Leave an AD domain. Windows XP disables the machine account.
861 We'll try the same. The old code would do an LDAP delete.
862 That only worked using the machine creds because added the machine
863 with full control to the computer object's ACL.
864 *******************************************************************/
866 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
868 TALLOC_CTX *ctx;
869 struct libnet_UnjoinCtx *r = NULL;
870 WERROR werr;
872 if (c->display_usage) {
873 d_printf("Usage:\n"
874 "net ads leave\n"
875 " Leave an AD domain\n");
876 return 0;
879 if (!*lp_realm()) {
880 d_fprintf(stderr, "No realm set, are we joined ?\n");
881 return -1;
884 if (!(ctx = talloc_init("net_ads_leave"))) {
885 d_fprintf(stderr, "Could not initialise talloc context.\n");
886 return -1;
889 if (!c->opt_kerberos) {
890 use_in_memory_ccache();
893 werr = libnet_init_UnjoinCtx(ctx, &r);
894 if (!W_ERROR_IS_OK(werr)) {
895 d_fprintf(stderr, "Could not initialise unjoin context.\n");
896 return -1;
899 r->in.debug = true;
900 r->in.use_kerberos = c->opt_kerberos;
901 r->in.dc_name = c->opt_host;
902 r->in.domain_name = lp_realm();
903 r->in.admin_account = c->opt_user_name;
904 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
905 r->in.modify_config = lp_config_backend_is_registry();
906 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
907 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
909 werr = libnet_Unjoin(ctx, r);
910 if (!W_ERROR_IS_OK(werr)) {
911 d_printf("Failed to leave domain: %s\n",
912 r->out.error_string ? r->out.error_string :
913 get_friendly_werror_msg(werr));
914 goto done;
917 if (W_ERROR_IS_OK(werr)) {
918 d_printf("Deleted account for '%s' in realm '%s'\n",
919 r->in.machine_name, r->out.dns_domain_name);
920 goto done;
923 /* We couldn't delete it - see if the disable succeeded. */
924 if (r->out.disabled_machine_account) {
925 d_printf("Disabled account for '%s' in realm '%s'\n",
926 r->in.machine_name, r->out.dns_domain_name);
927 werr = WERR_OK;
928 goto done;
931 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
932 r->in.machine_name, r->out.dns_domain_name);
934 done:
935 TALLOC_FREE(r);
936 TALLOC_FREE(ctx);
938 if (W_ERROR_IS_OK(werr)) {
939 return 0;
942 return -1;
945 static NTSTATUS net_ads_join_ok(struct net_context *c)
947 ADS_STRUCT *ads = NULL;
948 ADS_STATUS status;
950 if (!secrets_init()) {
951 DEBUG(1,("Failed to initialise secrets database\n"));
952 return NT_STATUS_ACCESS_DENIED;
955 net_use_krb_machine_account(c);
957 status = ads_startup(c, true, &ads);
958 if (!ADS_ERR_OK(status)) {
959 return ads_ntstatus(status);
962 ads_destroy(&ads);
963 return NT_STATUS_OK;
967 check that an existing join is OK
969 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
971 NTSTATUS status;
972 use_in_memory_ccache();
974 if (c->display_usage) {
975 d_printf("Usage:\n"
976 "net ads testjoin\n"
977 " Test if the existing join is ok\n");
978 return 0;
981 /* Display success or failure */
982 status = net_ads_join_ok(c);
983 if (!NT_STATUS_IS_OK(status)) {
984 fprintf(stderr,"Join to domain is not valid: %s\n",
985 get_friendly_nt_error_msg(status));
986 return -1;
989 printf("Join is OK\n");
990 return 0;
993 /*******************************************************************
994 Simple configu checks before beginning the join
995 ********************************************************************/
997 static WERROR check_ads_config( void )
999 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1000 d_printf("Host is not configured as a member server.\n");
1001 return WERR_INVALID_DOMAIN_ROLE;
1004 if (strlen(global_myname()) > 15) {
1005 d_printf("Our netbios name can be at most 15 chars long, "
1006 "\"%s\" is %u chars long\n", global_myname(),
1007 (unsigned int)strlen(global_myname()));
1008 return WERR_INVALID_COMPUTERNAME;
1011 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1012 d_fprintf(stderr, "realm must be set in in %s for ADS "
1013 "join to succeed.\n", get_dyn_CONFIGFILE());
1014 return WERR_INVALID_PARAM;
1017 return WERR_OK;
1020 /*******************************************************************
1021 Send a DNS update request
1022 *******************************************************************/
1024 #if defined(WITH_DNS_UPDATES)
1025 #include "dns.h"
1026 DNS_ERROR DoDNSUpdate(char *pszServerName,
1027 const char *pszDomainName, const char *pszHostName,
1028 const struct sockaddr_storage *sslist,
1029 size_t num_addrs );
1031 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1032 const char *machine_name,
1033 const struct sockaddr_storage *addrs,
1034 int num_addrs)
1036 struct dns_rr_ns *nameservers = NULL;
1037 int ns_count = 0;
1038 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1039 DNS_ERROR dns_err;
1040 fstring dns_server;
1041 const char *dnsdomain = NULL;
1042 char *root_domain = NULL;
1044 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1045 d_printf("No DNS domain configured for %s. "
1046 "Unable to perform DNS Update.\n", machine_name);
1047 status = NT_STATUS_INVALID_PARAMETER;
1048 goto done;
1050 dnsdomain++;
1052 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1053 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1054 /* Child domains often do not have NS records. Look
1055 for the NS record for the forest root domain
1056 (rootDomainNamingContext in therootDSE) */
1058 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1059 LDAPMessage *msg = NULL;
1060 char *root_dn;
1061 ADS_STATUS ads_status;
1063 if ( !ads->ldap.ld ) {
1064 ads_status = ads_connect( ads );
1065 if ( !ADS_ERR_OK(ads_status) ) {
1066 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1067 goto done;
1071 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1072 "(objectclass=*)", rootname_attrs, &msg);
1073 if (!ADS_ERR_OK(ads_status)) {
1074 goto done;
1077 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1078 if ( !root_dn ) {
1079 ads_msgfree( ads, msg );
1080 goto done;
1083 root_domain = ads_build_domain( root_dn );
1085 /* cleanup */
1086 ads_msgfree( ads, msg );
1088 /* try again for NS servers */
1090 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1092 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1093 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1094 "realm\n", ads->config.realm));
1095 goto done;
1098 dnsdomain = root_domain;
1102 /* Now perform the dns update - we'll try non-secure and if we fail,
1103 we'll follow it up with a secure update */
1105 fstrcpy( dns_server, nameservers[0].hostname );
1107 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1108 if (!ERR_DNS_IS_OK(dns_err)) {
1109 status = NT_STATUS_UNSUCCESSFUL;
1112 done:
1114 SAFE_FREE( root_domain );
1116 return status;
1119 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1121 int num_addrs;
1122 struct sockaddr_storage *iplist = NULL;
1123 fstring machine_name;
1124 NTSTATUS status;
1126 name_to_fqdn( machine_name, global_myname() );
1127 strlower_m( machine_name );
1129 /* Get our ip address (not the 127.0.0.x address but a real ip
1130 * address) */
1132 num_addrs = get_my_ip_address( &iplist );
1133 if ( num_addrs <= 0 ) {
1134 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1135 "addresses!\n"));
1136 return NT_STATUS_INVALID_PARAMETER;
1139 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1140 iplist, num_addrs);
1141 SAFE_FREE( iplist );
1142 return status;
1144 #endif
1147 /*******************************************************************
1148 ********************************************************************/
1150 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1152 d_printf("net ads join [options]\n");
1153 d_printf("Valid options:\n");
1154 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1155 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1156 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1157 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1158 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1159 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1160 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1161 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1162 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1163 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1164 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1165 d_printf(" the two other attributes.\n");
1167 return -1;
1170 /*******************************************************************
1171 ********************************************************************/
1173 int net_ads_join(struct net_context *c, int argc, const char **argv)
1175 TALLOC_CTX *ctx = NULL;
1176 struct libnet_JoinCtx *r = NULL;
1177 const char *domain = lp_realm();
1178 WERROR werr = WERR_SETUP_NOT_JOINED;
1179 bool createupn = false;
1180 const char *machineupn = NULL;
1181 const char *create_in_ou = NULL;
1182 int i;
1183 const char *os_name = NULL;
1184 const char *os_version = NULL;
1185 bool modify_config = lp_config_backend_is_registry();
1187 if (c->display_usage)
1188 return net_ads_join_usage(c, argc, argv);
1190 if (!modify_config) {
1192 werr = check_ads_config();
1193 if (!W_ERROR_IS_OK(werr)) {
1194 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1195 goto fail;
1199 if (!(ctx = talloc_init("net_ads_join"))) {
1200 d_fprintf(stderr, "Could not initialise talloc context.\n");
1201 werr = WERR_NOMEM;
1202 goto fail;
1205 if (!c->opt_kerberos) {
1206 use_in_memory_ccache();
1209 werr = libnet_init_JoinCtx(ctx, &r);
1210 if (!W_ERROR_IS_OK(werr)) {
1211 goto fail;
1214 /* process additional command line args */
1216 for ( i=0; i<argc; i++ ) {
1217 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1218 createupn = true;
1219 machineupn = get_string_param(argv[i]);
1221 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1222 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1223 d_fprintf(stderr, "Please supply a valid OU path.\n");
1224 werr = WERR_INVALID_PARAM;
1225 goto fail;
1228 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1229 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1230 d_fprintf(stderr, "Please supply a operating system name.\n");
1231 werr = WERR_INVALID_PARAM;
1232 goto fail;
1235 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1236 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1237 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1238 werr = WERR_INVALID_PARAM;
1239 goto fail;
1242 else {
1243 domain = argv[i];
1247 if (!*domain) {
1248 d_fprintf(stderr, "Please supply a valid domain name\n");
1249 werr = WERR_INVALID_PARAM;
1250 goto fail;
1253 /* Do the domain join here */
1255 r->in.domain_name = domain;
1256 r->in.create_upn = createupn;
1257 r->in.upn = machineupn;
1258 r->in.account_ou = create_in_ou;
1259 r->in.os_name = os_name;
1260 r->in.os_version = os_version;
1261 r->in.dc_name = c->opt_host;
1262 r->in.admin_account = c->opt_user_name;
1263 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1264 r->in.debug = true;
1265 r->in.use_kerberos = c->opt_kerberos;
1266 r->in.modify_config = modify_config;
1267 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1268 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1269 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1271 werr = libnet_Join(ctx, r);
1272 if (!W_ERROR_IS_OK(werr)) {
1273 goto fail;
1276 /* Check the short name of the domain */
1278 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1279 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1280 d_printf("domain name obtained from the server.\n");
1281 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1282 d_printf("You should set \"workgroup = %s\" in %s.\n",
1283 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1286 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1288 if (r->out.dns_domain_name) {
1289 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1290 r->out.dns_domain_name);
1291 } else {
1292 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1293 r->out.netbios_domain_name);
1296 #if defined(WITH_DNS_UPDATES)
1297 if (r->out.domain_is_ad) {
1298 /* We enter this block with user creds */
1299 ADS_STRUCT *ads_dns = NULL;
1301 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1302 /* kinit with the machine password */
1304 use_in_memory_ccache();
1305 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1306 goto fail;
1308 ads_dns->auth.password = secrets_fetch_machine_password(
1309 r->out.netbios_domain_name, NULL, NULL );
1310 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1311 strupper_m(ads_dns->auth.realm );
1312 ads_kinit_password( ads_dns );
1315 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1316 d_fprintf( stderr, "DNS update failed!\n" );
1319 /* exit from this block using machine creds */
1320 ads_destroy(&ads_dns);
1322 #endif
1323 TALLOC_FREE(r);
1324 TALLOC_FREE( ctx );
1326 return 0;
1328 fail:
1329 /* issue an overall failure message at the end. */
1330 d_printf("Failed to join domain: %s\n",
1331 r && r->out.error_string ? r->out.error_string :
1332 get_friendly_werror_msg(werr));
1333 TALLOC_FREE( ctx );
1335 return -1;
1338 /*******************************************************************
1339 ********************************************************************/
1341 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1343 #if defined(WITH_DNS_UPDATES)
1344 ADS_STRUCT *ads;
1345 ADS_STATUS status;
1346 TALLOC_CTX *ctx;
1348 #ifdef DEVELOPER
1349 talloc_enable_leak_report();
1350 #endif
1352 if (argc > 0 || c->display_usage) {
1353 d_printf("Usage:\n"
1354 "net ads dns register\n"
1355 " Register hostname with DNS\n");
1356 return -1;
1359 if (!(ctx = talloc_init("net_ads_dns"))) {
1360 d_fprintf(stderr, "Could not initialise talloc context\n");
1361 return -1;
1364 status = ads_startup(c, true, &ads);
1365 if ( !ADS_ERR_OK(status) ) {
1366 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1367 TALLOC_FREE(ctx);
1368 return -1;
1371 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1372 d_fprintf( stderr, "DNS update failed!\n" );
1373 ads_destroy( &ads );
1374 TALLOC_FREE( ctx );
1375 return -1;
1378 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1380 ads_destroy(&ads);
1381 TALLOC_FREE( ctx );
1383 return 0;
1384 #else
1385 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1386 return -1;
1387 #endif
1390 #if defined(WITH_DNS_UPDATES)
1391 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1392 #endif
1394 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1396 #if defined(WITH_DNS_UPDATES)
1397 DNS_ERROR err;
1399 #ifdef DEVELOPER
1400 talloc_enable_leak_report();
1401 #endif
1403 if (argc != 2 || c->display_usage) {
1404 d_printf("Usage:\n"
1405 "net ads dns gethostbyname <server> <name>\n"
1406 " Look up hostname from the AD\n"
1407 " server\tName server to use\n"
1408 " name\tName to look up\n");
1409 return -1;
1412 err = do_gethostbyname(argv[0], argv[1]);
1414 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1415 #endif
1416 return 0;
1419 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1421 struct functable func[] = {
1423 "register",
1424 net_ads_dns_register,
1425 NET_TRANSPORT_ADS,
1426 "Add host dns entry to AD",
1427 "net ads dns register\n"
1428 " Add host dns entry to AD"
1431 "gethostbyname",
1432 net_ads_dns_gethostbyname,
1433 NET_TRANSPORT_ADS,
1434 "Look up host",
1435 "net ads dns gethostbyname\n"
1436 " Look up host"
1438 {NULL, NULL, 0, NULL, NULL}
1441 return net_run_function(c, argc, argv, "net ads dns", func);
1444 /*******************************************************************
1445 ********************************************************************/
1447 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1449 d_printf(
1450 "\nnet ads printer search <printer>"
1451 "\n\tsearch for a printer in the directory\n"
1452 "\nnet ads printer info <printer> <server>"
1453 "\n\tlookup info in directory for printer on server"
1454 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1455 "\nnet ads printer publish <printername>"
1456 "\n\tpublish printer in directory"
1457 "\n\t(note: printer name is required)\n"
1458 "\nnet ads printer remove <printername>"
1459 "\n\tremove printer from directory"
1460 "\n\t(note: printer name is required)\n");
1461 return -1;
1464 /*******************************************************************
1465 ********************************************************************/
1467 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1469 ADS_STRUCT *ads;
1470 ADS_STATUS rc;
1471 LDAPMessage *res = NULL;
1473 if (c->display_usage) {
1474 d_printf("Usage:\n"
1475 "net ads printer search\n"
1476 " List printers in the AD\n");
1477 return 0;
1480 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1481 return -1;
1484 rc = ads_find_printers(ads, &res);
1486 if (!ADS_ERR_OK(rc)) {
1487 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1488 ads_msgfree(ads, res);
1489 ads_destroy(&ads);
1490 return -1;
1493 if (ads_count_replies(ads, res) == 0) {
1494 d_fprintf(stderr, "No results found\n");
1495 ads_msgfree(ads, res);
1496 ads_destroy(&ads);
1497 return -1;
1500 ads_dump(ads, res);
1501 ads_msgfree(ads, res);
1502 ads_destroy(&ads);
1503 return 0;
1506 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1508 ADS_STRUCT *ads;
1509 ADS_STATUS rc;
1510 const char *servername, *printername;
1511 LDAPMessage *res = NULL;
1513 if (c->display_usage) {
1514 d_printf("Usage:\n"
1515 "net ads printer info [printername [servername]]\n"
1516 " Display printer info from AD\n"
1517 " printername\tPrinter name or wildcard\n"
1518 " servername\tName of the print server\n");
1519 return 0;
1522 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1523 return -1;
1526 if (argc > 0) {
1527 printername = argv[0];
1528 } else {
1529 printername = "*";
1532 if (argc > 1) {
1533 servername = argv[1];
1534 } else {
1535 servername = global_myname();
1538 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1540 if (!ADS_ERR_OK(rc)) {
1541 d_fprintf(stderr, "Server '%s' not found: %s\n",
1542 servername, ads_errstr(rc));
1543 ads_msgfree(ads, res);
1544 ads_destroy(&ads);
1545 return -1;
1548 if (ads_count_replies(ads, res) == 0) {
1549 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1550 ads_msgfree(ads, res);
1551 ads_destroy(&ads);
1552 return -1;
1555 ads_dump(ads, res);
1556 ads_msgfree(ads, res);
1557 ads_destroy(&ads);
1559 return 0;
1562 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1564 ADS_STRUCT *ads;
1565 ADS_STATUS rc;
1566 const char *servername, *printername;
1567 struct cli_state *cli;
1568 struct rpc_pipe_client *pipe_hnd;
1569 struct sockaddr_storage server_ss;
1570 NTSTATUS nt_status;
1571 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1572 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1573 char *prt_dn, *srv_dn, **srv_cn;
1574 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1575 LDAPMessage *res = NULL;
1577 if (argc < 1 || c->display_usage) {
1578 d_printf("Usage:\n"
1579 "net ads printer publish <printername> [servername]\n"
1580 " Publish printer in AD\n"
1581 " printername\tName of the printer\n"
1582 " servername\tName of the print server\n");
1583 talloc_destroy(mem_ctx);
1584 return -1;
1587 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1588 talloc_destroy(mem_ctx);
1589 return -1;
1592 printername = argv[0];
1594 if (argc == 2) {
1595 servername = argv[1];
1596 } else {
1597 servername = global_myname();
1600 /* Get printer data from SPOOLSS */
1602 resolve_name(servername, &server_ss, 0x20);
1604 nt_status = cli_full_connection(&cli, global_myname(), servername,
1605 &server_ss, 0,
1606 "IPC$", "IPC",
1607 c->opt_user_name, c->opt_workgroup,
1608 c->opt_password ? c->opt_password : "",
1609 CLI_FULL_CONNECTION_USE_KERBEROS,
1610 Undefined, NULL);
1612 if (NT_STATUS_IS_ERR(nt_status)) {
1613 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1614 "for %s\n", servername, printername);
1615 ads_destroy(&ads);
1616 talloc_destroy(mem_ctx);
1617 return -1;
1620 /* Publish on AD server */
1622 ads_find_machine_acct(ads, &res, servername);
1624 if (ads_count_replies(ads, res) == 0) {
1625 d_fprintf(stderr, "Could not find machine account for server %s\n",
1626 servername);
1627 ads_destroy(&ads);
1628 talloc_destroy(mem_ctx);
1629 return -1;
1632 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1633 srv_cn = ldap_explode_dn(srv_dn, 1);
1635 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1636 printername_escaped = escape_rdn_val_string_alloc(printername);
1637 if (!srv_cn_escaped || !printername_escaped) {
1638 SAFE_FREE(srv_cn_escaped);
1639 SAFE_FREE(printername_escaped);
1640 d_fprintf(stderr, "Internal error, out of memory!");
1641 ads_destroy(&ads);
1642 talloc_destroy(mem_ctx);
1643 return -1;
1646 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1647 SAFE_FREE(srv_cn_escaped);
1648 SAFE_FREE(printername_escaped);
1649 d_fprintf(stderr, "Internal error, out of memory!");
1650 ads_destroy(&ads);
1651 talloc_destroy(mem_ctx);
1652 return -1;
1655 SAFE_FREE(srv_cn_escaped);
1656 SAFE_FREE(printername_escaped);
1658 nt_status = cli_rpc_pipe_open_noauth(cli, &syntax_spoolss, &pipe_hnd);
1659 if (!NT_STATUS_IS_OK(nt_status)) {
1660 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1661 servername);
1662 SAFE_FREE(prt_dn);
1663 ads_destroy(&ads);
1664 talloc_destroy(mem_ctx);
1665 return -1;
1668 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1669 printername))) {
1670 SAFE_FREE(prt_dn);
1671 ads_destroy(&ads);
1672 talloc_destroy(mem_ctx);
1673 return -1;
1676 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1677 if (!ADS_ERR_OK(rc)) {
1678 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1679 SAFE_FREE(prt_dn);
1680 ads_destroy(&ads);
1681 talloc_destroy(mem_ctx);
1682 return -1;
1685 d_printf("published printer\n");
1686 SAFE_FREE(prt_dn);
1687 ads_destroy(&ads);
1688 talloc_destroy(mem_ctx);
1690 return 0;
1693 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1695 ADS_STRUCT *ads;
1696 ADS_STATUS rc;
1697 const char *servername;
1698 char *prt_dn;
1699 LDAPMessage *res = NULL;
1701 if (argc < 1 || c->display_usage) {
1702 d_printf("Usage:\n"
1703 "net ads printer remove <printername> [servername]\n"
1704 " Remove a printer from the AD\n"
1705 " printername\tName of the printer\n"
1706 " servername\tName of the print server\n");
1707 return -1;
1710 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1711 return -1;
1714 if (argc > 1) {
1715 servername = argv[1];
1716 } else {
1717 servername = global_myname();
1720 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1722 if (!ADS_ERR_OK(rc)) {
1723 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1724 ads_msgfree(ads, res);
1725 ads_destroy(&ads);
1726 return -1;
1729 if (ads_count_replies(ads, res) == 0) {
1730 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1731 ads_msgfree(ads, res);
1732 ads_destroy(&ads);
1733 return -1;
1736 prt_dn = ads_get_dn(ads, res);
1737 ads_msgfree(ads, res);
1738 rc = ads_del_dn(ads, prt_dn);
1739 ads_memfree(ads, prt_dn);
1741 if (!ADS_ERR_OK(rc)) {
1742 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1743 ads_destroy(&ads);
1744 return -1;
1747 ads_destroy(&ads);
1748 return 0;
1751 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1753 struct functable func[] = {
1755 "search",
1756 net_ads_printer_search,
1757 NET_TRANSPORT_ADS,
1758 "Search for a printer",
1759 "net ads printer search\n"
1760 " Search for a printer"
1763 "info",
1764 net_ads_printer_info,
1765 NET_TRANSPORT_ADS,
1766 "Display printer information",
1767 "net ads printer info\n"
1768 " Display printer information"
1771 "publish",
1772 net_ads_printer_publish,
1773 NET_TRANSPORT_ADS,
1774 "Publish a printer",
1775 "net ads printer publish\n"
1776 " Publish a printer"
1779 "remove",
1780 net_ads_printer_remove,
1781 NET_TRANSPORT_ADS,
1782 "Delete a printer",
1783 "net ads printer remove\n"
1784 " Delete a printer"
1786 {NULL, NULL, 0, NULL, NULL}
1789 return net_run_function(c, argc, argv, "net ads printer", func);
1793 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1795 ADS_STRUCT *ads;
1796 const char *auth_principal = c->opt_user_name;
1797 const char *auth_password = c->opt_password;
1798 char *realm = NULL;
1799 char *new_password = NULL;
1800 char *chr, *prompt;
1801 const char *user;
1802 ADS_STATUS ret;
1804 if (c->display_usage) {
1805 d_printf("Usage:\n"
1806 "net ads password <username>\n"
1807 " Change password for user\n"
1808 " username\tName of user to change password for\n");
1809 return 0;
1812 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1813 d_fprintf(stderr, "You must supply an administrator username/password\n");
1814 return -1;
1817 if (argc < 1) {
1818 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1819 return -1;
1822 user = argv[0];
1823 if (!strchr_m(user, '@')) {
1824 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1825 return -1;
1827 user = chr;
1830 use_in_memory_ccache();
1831 chr = strchr_m(auth_principal, '@');
1832 if (chr) {
1833 realm = ++chr;
1834 } else {
1835 realm = lp_realm();
1838 /* use the realm so we can eventually change passwords for users
1839 in realms other than default */
1840 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1841 return -1;
1844 /* we don't actually need a full connect, but it's the easy way to
1845 fill in the KDC's addresss */
1846 ads_connect(ads);
1848 if (!ads->config.realm) {
1849 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1850 return -1;
1853 if (argv[1]) {
1854 new_password = (char *)argv[1];
1855 } else {
1856 if (asprintf(&prompt, "Enter new password for %s:", user) == -1) {
1857 return -1;
1859 new_password = getpass(prompt);
1860 free(prompt);
1863 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1864 auth_password, user, new_password, ads->auth.time_offset);
1865 if (!ADS_ERR_OK(ret)) {
1866 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1867 ads_destroy(&ads);
1868 return -1;
1871 d_printf("Password change for %s completed.\n", user);
1872 ads_destroy(&ads);
1874 return 0;
1877 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1879 ADS_STRUCT *ads;
1880 char *host_principal;
1881 fstring my_name;
1882 ADS_STATUS ret;
1884 if (c->display_usage) {
1885 d_printf("Usage:\n"
1886 "net ads changetrustpw\n"
1887 " Change the machine account's trust password\n");
1888 return 0;
1891 if (!secrets_init()) {
1892 DEBUG(1,("Failed to initialise secrets database\n"));
1893 return -1;
1896 net_use_krb_machine_account(c);
1898 use_in_memory_ccache();
1900 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1901 return -1;
1904 fstrcpy(my_name, global_myname());
1905 strlower_m(my_name);
1906 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
1907 ads_destroy(&ads);
1908 return -1;
1910 d_printf("Changing password for principal: %s\n", host_principal);
1912 ret = ads_change_trust_account_password(ads, host_principal);
1914 if (!ADS_ERR_OK(ret)) {
1915 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1916 ads_destroy(&ads);
1917 SAFE_FREE(host_principal);
1918 return -1;
1921 d_printf("Password change for principal %s succeeded.\n", host_principal);
1923 if (lp_use_kerberos_keytab()) {
1924 d_printf("Attempting to update system keytab with new password.\n");
1925 if (ads_keytab_create_default(ads)) {
1926 d_printf("Failed to update system keytab.\n");
1930 ads_destroy(&ads);
1931 SAFE_FREE(host_principal);
1933 return 0;
1937 help for net ads search
1939 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
1941 d_printf(
1942 "\nnet ads search <expression> <attributes...>\n"
1943 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1944 "The expression is a standard LDAP search expression, and the\n"
1945 "attributes are a list of LDAP fields to show in the results.\n\n"
1946 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1948 net_common_flags_usage(c, argc, argv);
1949 return -1;
1954 general ADS search function. Useful in diagnosing problems in ADS
1956 static int net_ads_search(struct net_context *c, int argc, const char **argv)
1958 ADS_STRUCT *ads;
1959 ADS_STATUS rc;
1960 const char *ldap_exp;
1961 const char **attrs;
1962 LDAPMessage *res = NULL;
1964 if (argc < 1 || c->display_usage) {
1965 return net_ads_search_usage(c, argc, argv);
1968 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1969 return -1;
1972 ldap_exp = argv[0];
1973 attrs = (argv + 1);
1975 rc = ads_do_search_all(ads, ads->config.bind_path,
1976 LDAP_SCOPE_SUBTREE,
1977 ldap_exp, attrs, &res);
1978 if (!ADS_ERR_OK(rc)) {
1979 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1980 ads_destroy(&ads);
1981 return -1;
1984 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1986 /* dump the results */
1987 ads_dump(ads, res);
1989 ads_msgfree(ads, res);
1990 ads_destroy(&ads);
1992 return 0;
1997 help for net ads search
1999 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2001 d_printf(
2002 "\nnet ads dn <dn> <attributes...>\n"
2003 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2004 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2005 "to show in the results\n\n"
2006 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2007 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2009 net_common_flags_usage(c, argc, argv);
2010 return -1;
2015 general ADS search function. Useful in diagnosing problems in ADS
2017 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2019 ADS_STRUCT *ads;
2020 ADS_STATUS rc;
2021 const char *dn;
2022 const char **attrs;
2023 LDAPMessage *res = NULL;
2025 if (argc < 1 || c->display_usage) {
2026 return net_ads_dn_usage(c, argc, argv);
2029 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2030 return -1;
2033 dn = argv[0];
2034 attrs = (argv + 1);
2036 rc = ads_do_search_all(ads, dn,
2037 LDAP_SCOPE_BASE,
2038 "(objectclass=*)", attrs, &res);
2039 if (!ADS_ERR_OK(rc)) {
2040 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2041 ads_destroy(&ads);
2042 return -1;
2045 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2047 /* dump the results */
2048 ads_dump(ads, res);
2050 ads_msgfree(ads, res);
2051 ads_destroy(&ads);
2053 return 0;
2057 help for net ads sid search
2059 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2061 d_printf(
2062 "\nnet ads sid <sid> <attributes...>\n"
2063 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2064 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2065 "to show in the results\n\n"
2066 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2068 net_common_flags_usage(c, argc, argv);
2069 return -1;
2074 general ADS search function. Useful in diagnosing problems in ADS
2076 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2078 ADS_STRUCT *ads;
2079 ADS_STATUS rc;
2080 const char *sid_string;
2081 const char **attrs;
2082 LDAPMessage *res = NULL;
2083 DOM_SID sid;
2085 if (argc < 1 || c->display_usage) {
2086 return net_ads_sid_usage(c, argc, argv);
2089 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2090 return -1;
2093 sid_string = argv[0];
2094 attrs = (argv + 1);
2096 if (!string_to_sid(&sid, sid_string)) {
2097 d_fprintf(stderr, "could not convert sid\n");
2098 ads_destroy(&ads);
2099 return -1;
2102 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2103 if (!ADS_ERR_OK(rc)) {
2104 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2105 ads_destroy(&ads);
2106 return -1;
2109 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2111 /* dump the results */
2112 ads_dump(ads, res);
2114 ads_msgfree(ads, res);
2115 ads_destroy(&ads);
2117 return 0;
2120 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2122 int ret;
2123 ADS_STRUCT *ads;
2125 if (c->display_usage) {
2126 d_printf("Usage:\n"
2127 "net ads keytab flush\n"
2128 " Delete the whole keytab\n");
2129 return 0;
2132 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2133 return -1;
2135 ret = ads_keytab_flush(ads);
2136 ads_destroy(&ads);
2137 return ret;
2140 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2142 int i;
2143 int ret = 0;
2144 ADS_STRUCT *ads;
2146 if (c->display_usage) {
2147 d_printf("Usage:\n"
2148 "net ads keytab add <principal> [principal ...]\n"
2149 " Add principals to local keytab\n"
2150 " principal\tKerberos principal to add to "
2151 "keytab\n");
2152 return 0;
2155 d_printf("Processing principals to add...\n");
2156 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2157 return -1;
2159 for (i = 0; i < argc; i++) {
2160 ret |= ads_keytab_add_entry(ads, argv[i]);
2162 ads_destroy(&ads);
2163 return ret;
2166 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2168 ADS_STRUCT *ads;
2169 int ret;
2171 if (c->display_usage) {
2172 d_printf("Usage:\n"
2173 "net ads keytab create\n"
2174 " Create new default keytab\n");
2175 return 0;
2178 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2179 return -1;
2181 ret = ads_keytab_create_default(ads);
2182 ads_destroy(&ads);
2183 return ret;
2186 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2188 const char *keytab = NULL;
2190 if (c->display_usage) {
2191 d_printf("Usage:\n"
2192 "net ads keytab list [keytab]\n"
2193 " List a local keytab\n"
2194 " keytab\tKeytab to list\n");
2195 return 0;
2198 if (argc >= 1) {
2199 keytab = argv[0];
2202 return ads_keytab_list(keytab);
2206 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2208 struct functable func[] = {
2210 "add",
2211 net_ads_keytab_add,
2212 NET_TRANSPORT_ADS,
2213 "Add a service principal",
2214 "net ads keytab add\n"
2215 " Add a service principal"
2218 "create",
2219 net_ads_keytab_create,
2220 NET_TRANSPORT_ADS,
2221 "Create a fresh keytab",
2222 "net ads keytab create\n"
2223 " Create a fresh keytab"
2226 "flush",
2227 net_ads_keytab_flush,
2228 NET_TRANSPORT_ADS,
2229 "Remove all keytab entries",
2230 "net ads keytab flush\n"
2231 " Remove all keytab entries"
2234 "list",
2235 net_ads_keytab_list,
2236 NET_TRANSPORT_ADS,
2237 "List a keytab",
2238 "net ads keytab list\n"
2239 " List a keytab"
2241 {NULL, NULL, 0, NULL, NULL}
2244 if (!lp_use_kerberos_keytab()) {
2245 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2246 use keytab functions.\n");
2249 return net_run_function(c, argc, argv, "net ads keytab", func);
2252 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2254 int ret = -1;
2256 if (c->display_usage) {
2257 d_printf("Usage:\n"
2258 "net ads kerberos renew\n"
2259 " Renew TGT from existing credential cache\n");
2260 return 0;
2263 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2264 if (ret) {
2265 d_printf("failed to renew kerberos ticket: %s\n",
2266 error_message(ret));
2268 return ret;
2271 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2273 struct PAC_DATA *pac = NULL;
2274 struct PAC_LOGON_INFO *info = NULL;
2275 TALLOC_CTX *mem_ctx = NULL;
2276 NTSTATUS status;
2277 int ret = -1;
2279 if (c->display_usage) {
2280 d_printf("Usage:\n"
2281 "net ads kerberos pac\n"
2282 " Dump the Kerberos PAC\n");
2283 return 0;
2286 mem_ctx = talloc_init("net_ads_kerberos_pac");
2287 if (!mem_ctx) {
2288 goto out;
2291 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2293 status = kerberos_return_pac(mem_ctx,
2294 c->opt_user_name,
2295 c->opt_password,
2297 NULL,
2298 NULL,
2299 NULL,
2300 true,
2301 true,
2302 2592000, /* one month */
2303 &pac);
2304 if (!NT_STATUS_IS_OK(status)) {
2305 d_printf("failed to query kerberos PAC: %s\n",
2306 nt_errstr(status));
2307 goto out;
2310 info = get_logon_info_from_pac(pac);
2311 if (info) {
2312 const char *s;
2313 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2314 d_printf("The Pac: %s\n", s);
2317 ret = 0;
2318 out:
2319 TALLOC_FREE(mem_ctx);
2320 return ret;
2323 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2325 TALLOC_CTX *mem_ctx = NULL;
2326 int ret = -1;
2327 NTSTATUS status;
2329 if (c->display_usage) {
2330 d_printf("Usage:\n"
2331 "net ads kerberos kinit\n"
2332 " Get Ticket Granting Ticket (TGT) for the user\n");
2333 return 0;
2336 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2337 if (!mem_ctx) {
2338 goto out;
2341 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2343 ret = kerberos_kinit_password_ext(c->opt_user_name,
2344 c->opt_password,
2346 NULL,
2347 NULL,
2348 NULL,
2349 true,
2350 true,
2351 2592000, /* one month */
2352 &status);
2353 if (ret) {
2354 d_printf("failed to kinit password: %s\n",
2355 nt_errstr(status));
2357 out:
2358 return ret;
2361 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2363 struct functable func[] = {
2365 "kinit",
2366 net_ads_kerberos_kinit,
2367 NET_TRANSPORT_ADS,
2368 "Retrieve Ticket Granting Ticket (TGT)",
2369 "net ads kerberos kinit\n"
2370 " Receive Ticket Granting Ticket (TGT)"
2373 "renew",
2374 net_ads_kerberos_renew,
2375 NET_TRANSPORT_ADS,
2376 "Renew Ticket Granting Ticket from credential cache"
2377 "net ads kerberos renew\n"
2378 " Renew Ticket Granting Ticket from credential cache"
2381 "pac",
2382 net_ads_kerberos_pac,
2383 NET_TRANSPORT_ADS,
2384 "Dump Kerberos PAC",
2385 "net ads kerberos pac\n"
2386 " Dump Kerberos PAC"
2388 {NULL, NULL, 0, NULL, NULL}
2391 return net_run_function(c, argc, argv, "net ads kerberos", func);
2394 int net_ads(struct net_context *c, int argc, const char **argv)
2396 struct functable func[] = {
2398 "info",
2399 net_ads_info,
2400 NET_TRANSPORT_ADS,
2401 "Display details on remote ADS server",
2402 "net ads info\n"
2403 " Display details on remote ADS server"
2406 "join",
2407 net_ads_join,
2408 NET_TRANSPORT_ADS,
2409 "Join the local machine to ADS realm",
2410 "net ads join\n"
2411 " Join the local machine to ADS realm"
2414 "testjoin",
2415 net_ads_testjoin,
2416 NET_TRANSPORT_ADS,
2417 "Validate machine account",
2418 "net ads testjoin\n"
2419 " Validate machine account"
2422 "leave",
2423 net_ads_leave,
2424 NET_TRANSPORT_ADS,
2425 "Remove the local machine from ADS",
2426 "net ads leave\n"
2427 " Remove the local machine from ADS"
2430 "status",
2431 net_ads_status,
2432 NET_TRANSPORT_ADS,
2433 "Display machine account details",
2434 "net ads status\n"
2435 " Display machine account details"
2438 "user",
2439 net_ads_user,
2440 NET_TRANSPORT_ADS,
2441 "List/modify users",
2442 "net ads user\n"
2443 " List/modify users"
2446 "group",
2447 net_ads_group,
2448 NET_TRANSPORT_ADS,
2449 "List/modify groups",
2450 "net ads group\n"
2451 " List/modify groups"
2454 "dns",
2455 net_ads_dns,
2456 NET_TRANSPORT_ADS,
2457 "Issue dynamic DNS update",
2458 "net ads dns\n"
2459 " Issue dynamic DNS update"
2462 "password",
2463 net_ads_password,
2464 NET_TRANSPORT_ADS,
2465 "Change user passwords",
2466 "net ads password\n"
2467 " Change user passwords"
2470 "changetrustpw",
2471 net_ads_changetrustpw,
2472 NET_TRANSPORT_ADS,
2473 "Change trust account password",
2474 "net ads changetrustpw\n"
2475 " Change trust account password"
2478 "printer",
2479 net_ads_printer,
2480 NET_TRANSPORT_ADS,
2481 "List/modify printer entries",
2482 "net ads printer\n"
2483 " List/modify printer entries"
2486 "search",
2487 net_ads_search,
2488 NET_TRANSPORT_ADS,
2489 "Issue LDAP search using filter",
2490 "net ads search\n"
2491 " Issue LDAP search using filter"
2494 "dn",
2495 net_ads_dn,
2496 NET_TRANSPORT_ADS,
2497 "Issue LDAP search by DN",
2498 "net ads dn\n"
2499 " Issue LDAP search by DN"
2502 "sid",
2503 net_ads_sid,
2504 NET_TRANSPORT_ADS,
2505 "Issue LDAP search by SID",
2506 "net ads sid\n"
2507 " Issue LDAP search by SID"
2510 "workgroup",
2511 net_ads_workgroup,
2512 NET_TRANSPORT_ADS,
2513 "Display workgroup name",
2514 "net ads workgroup\n"
2515 " Display the workgroup name"
2518 "lookup",
2519 net_ads_lookup,
2520 NET_TRANSPORT_ADS,
2521 "Perfom CLDAP query on DC",
2522 "net ads lookup\n"
2523 " Find the ADS DC using CLDAP lookups"
2526 "keytab",
2527 net_ads_keytab,
2528 NET_TRANSPORT_ADS,
2529 "Manage local keytab file",
2530 "net ads keytab\n"
2531 " Manage local keytab file"
2534 "gpo",
2535 net_ads_gpo,
2536 NET_TRANSPORT_ADS,
2537 "Manage group policy objects",
2538 "net ads gpo\n"
2539 " Manage group policy objects"
2542 "kerberos",
2543 net_ads_kerberos,
2544 NET_TRANSPORT_ADS,
2545 "Manage kerberos keytab",
2546 "net ads kerberos\n"
2547 " Manage kerberos keytab"
2549 {NULL, NULL, 0, NULL, NULL}
2552 return net_run_function(c, argc, argv, "net ads", func);
2555 #else
2557 static int net_ads_noads(void)
2559 d_fprintf(stderr, "ADS support not compiled in\n");
2560 return -1;
2563 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2565 return net_ads_noads();
2568 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2570 return net_ads_noads();
2573 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2575 return net_ads_noads();
2578 int net_ads_join(struct net_context *c, int argc, const char **argv)
2580 return net_ads_noads();
2583 int net_ads_user(struct net_context *c, int argc, const char **argv)
2585 return net_ads_noads();
2588 int net_ads_group(struct net_context *c, int argc, const char **argv)
2590 return net_ads_noads();
2593 /* this one shouldn't display a message */
2594 int net_ads_check(struct net_context *c)
2596 return -1;
2599 int net_ads_check_our_domain(struct net_context *c)
2601 return -1;
2604 int net_ads(struct net_context *c, int argc, const char **argv)
2606 return net_ads_noads();
2609 #endif /* WITH_ADS */