ntvfs: Simplify rap_netshareenum()
[samba.git] / source3 / utils / net_ads.c
blob0f1193d7ec0d70878aae6bb000b7b866f3a070eb
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 "libsmb/namequery.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "librpc/gen_ndr/ndr_krb5pac.h"
28 #include "../librpc/gen_ndr/ndr_spoolss.h"
29 #include "nsswitch/libwbclient/wbclient.h"
30 #include "ads.h"
31 #include "libads/cldap.h"
32 #include "../lib/addns/dnsquery.h"
33 #include "../libds/common/flags.h"
34 #include "librpc/gen_ndr/libnet_join.h"
35 #include "libnet/libnet_join.h"
36 #include "smb_krb5.h"
37 #include "secrets.h"
38 #include "../libcli/security/security.h"
39 #include "libsmb/libsmb.h"
40 #include "lib/param/loadparm.h"
41 #include "utils/net_dns.h"
42 #include "auth/kerberos/pac_utils.h"
43 #include "lib/util/string_wrappers.h"
44 #include "lib/util/util_file.h"
46 #ifdef HAVE_JANSSON
47 #include <jansson.h>
48 #include "audit_logging.h" /* various JSON helpers */
49 #include "auth/common_auth.h"
50 #endif /* [HAVE_JANSSON] */
52 #ifdef HAVE_ADS
54 /* when we do not have sufficient input parameters to contact a remote domain
55 * we always fall back to our own realm - Guenther*/
57 static const char *assume_own_realm(struct net_context *c)
59 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
60 return lp_realm();
63 return NULL;
66 #ifdef HAVE_JANSSON
69 * note: JSON output deliberately bypasses gettext so as to provide the same
70 * output irrespective of the locale.
73 static int output_json(const struct json_object *jsobj)
75 TALLOC_CTX *ctx = NULL;
76 char *json = NULL;
78 if (json_is_invalid(jsobj)) {
79 return -1;
82 ctx = talloc_new(NULL);
83 if (ctx == NULL) {
84 d_fprintf(stderr, _("Out of memory\n"));
85 return -1;
88 json = json_to_string(ctx, jsobj);
89 if (!json) {
90 d_fprintf(stderr, _("error encoding to JSON\n"));
91 return -1;
94 d_printf("%s\n", json);
95 TALLOC_FREE(ctx);
97 return 0;
100 static int net_ads_cldap_netlogon_json
101 (ADS_STRUCT *ads,
102 const char *addr,
103 const struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply)
105 struct json_object jsobj = json_new_object();
106 struct json_object flagsobj = json_new_object();
107 char response_type [32] = { '\0' };
108 int ret = 0;
110 if (json_is_invalid(&jsobj) || json_is_invalid(&flagsobj)) {
111 d_fprintf(stderr, _("error setting up JSON value\n"));
113 goto failure;
116 switch (reply->command) {
117 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
118 strncpy(response_type,
119 "LOGON_SAM_LOGON_USER_UNKNOWN_EX",
120 sizeof(response_type));
121 break;
122 case LOGON_SAM_LOGON_RESPONSE_EX:
123 strncpy(response_type,
124 "LOGON_SAM_LOGON_RESPONSE_EX",
125 sizeof(response_type));
126 break;
127 default:
128 snprintf(response_type,
129 sizeof(response_type),
130 "0x%x",
131 reply->command);
132 break;
135 ret = json_add_string(&jsobj, "Information for Domain Controller",
136 addr);
137 if (ret != 0) {
138 goto failure;
141 ret = json_add_string(&jsobj, "Response Type", response_type);
142 if (ret != 0) {
143 goto failure;
146 ret = json_add_guid(&jsobj, "GUID", &reply->domain_uuid);
147 if (ret != 0) {
148 goto failure;
151 ret = json_add_bool(&flagsobj, "Is a PDC",
152 reply->server_type & NBT_SERVER_PDC);
153 if (ret != 0) {
154 goto failure;
157 ret = json_add_bool(&flagsobj, "Is a GC of the forest",
158 reply->server_type & NBT_SERVER_GC);
159 if (ret != 0) {
160 goto failure;
163 ret = json_add_bool(&flagsobj, "Is an LDAP server",
164 reply->server_type & NBT_SERVER_LDAP);
165 if (ret != 0) {
166 goto failure;
169 ret = json_add_bool(&flagsobj, "Supports DS",
170 reply->server_type & NBT_SERVER_DS);
171 if (ret != 0) {
172 goto failure;
175 ret = json_add_bool(&flagsobj, "Is running a KDC",
176 reply->server_type & NBT_SERVER_KDC);
177 if (ret != 0) {
178 goto failure;
181 ret = json_add_bool(&flagsobj, "Is running time services",
182 reply->server_type & NBT_SERVER_TIMESERV);
183 if (ret != 0) {
184 goto failure;
187 ret = json_add_bool(&flagsobj, "Is the closest DC",
188 reply->server_type & NBT_SERVER_CLOSEST);
189 if (ret != 0) {
190 goto failure;
193 ret = json_add_bool(&flagsobj, "Is writable",
194 reply->server_type & NBT_SERVER_WRITABLE);
195 if (ret != 0) {
196 goto failure;
199 ret = json_add_bool(&flagsobj, "Has a hardware clock",
200 reply->server_type & NBT_SERVER_GOOD_TIMESERV);
201 if (ret != 0) {
202 goto failure;
205 ret = json_add_bool(&flagsobj,
206 "Is a non-domain NC serviced by LDAP server",
207 reply->server_type & NBT_SERVER_NDNC);
208 if (ret != 0) {
209 goto failure;
212 ret = json_add_bool
213 (&flagsobj, "Is NT6 DC that has some secrets",
214 reply->server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6);
215 if (ret != 0) {
216 goto failure;
219 ret = json_add_bool
220 (&flagsobj, "Is NT6 DC that has all secrets",
221 reply->server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6);
222 if (ret != 0) {
223 goto failure;
226 ret = json_add_bool(&flagsobj, "Runs Active Directory Web Services",
227 reply->server_type & NBT_SERVER_ADS_WEB_SERVICE);
228 if (ret != 0) {
229 goto failure;
232 ret = json_add_bool(&flagsobj, "Runs on Windows 2012 or later",
233 reply->server_type & NBT_SERVER_DS_8);
234 if (ret != 0) {
235 goto failure;
238 ret = json_add_bool(&flagsobj, "Runs on Windows 2012R2 or later",
239 reply->server_type & NBT_SERVER_DS_9);
240 if (ret != 0) {
241 goto failure;
244 ret = json_add_bool(&flagsobj, "Runs on Windows 2016 or later",
245 reply->server_type & NBT_SERVER_DS_10);
246 if (ret != 0) {
247 goto failure;
250 ret = json_add_bool(&flagsobj, "Has a DNS name",
251 reply->server_type & NBT_SERVER_HAS_DNS_NAME);
252 if (ret != 0) {
253 goto failure;
256 ret = json_add_bool(&flagsobj, "Is a default NC",
257 reply->server_type & NBT_SERVER_IS_DEFAULT_NC);
258 if (ret != 0) {
259 goto failure;
262 ret = json_add_bool(&flagsobj, "Is the forest root",
263 reply->server_type & NBT_SERVER_FOREST_ROOT);
264 if (ret != 0) {
265 goto failure;
268 ret = json_add_string(&jsobj, "Forest", reply->forest);
269 if (ret != 0) {
270 goto failure;
273 ret = json_add_string(&jsobj, "Domain", reply->dns_domain);
274 if (ret != 0) {
275 goto failure;
278 ret = json_add_string(&jsobj, "Domain Controller", reply->pdc_dns_name);
279 if (ret != 0) {
280 goto failure;
284 ret = json_add_string(&jsobj, "Pre-Win2k Domain", reply->domain_name);
285 if (ret != 0) {
286 goto failure;
289 ret = json_add_string(&jsobj, "Pre-Win2k Hostname", reply->pdc_name);
290 if (ret != 0) {
291 goto failure;
294 if (*reply->user_name) {
295 ret = json_add_string(&jsobj, "User name", reply->user_name);
296 if (ret != 0) {
297 goto failure;
301 ret = json_add_string(&jsobj, "Server Site Name", reply->server_site);
302 if (ret != 0) {
303 goto failure;
306 ret = json_add_string(&jsobj, "Client Site Name", reply->client_site);
307 if (ret != 0) {
308 goto failure;
311 ret = json_add_int(&jsobj, "NT Version", reply->nt_version);
312 if (ret != 0) {
313 goto failure;
316 ret = json_add_int(&jsobj, "LMNT Token", reply->lmnt_token);
317 if (ret != 0) {
318 goto failure;
321 ret = json_add_int(&jsobj, "LM20 Token", reply->lm20_token);
322 if (ret != 0) {
323 goto failure;
326 ret = json_add_object(&jsobj, "Flags", &flagsobj);
327 if (ret != 0) {
328 goto failure;
331 ret = output_json(&jsobj);
332 json_free(&jsobj); /* frees flagsobj recursively */
334 return ret;
336 failure:
337 json_free(&flagsobj);
338 json_free(&jsobj);
340 return ret;
343 #else /* [HAVE_JANSSON] */
345 static int net_ads_cldap_netlogon_json
346 (ADS_STRUCT *ads,
347 const char *addr,
348 const struct NETLOGON_SAM_LOGON_RESPONSE_EX * reply)
350 d_fprintf(stderr, _("JSON support not available\n"));
352 return -1;
355 #endif /* [HAVE_JANSSON] */
358 do a cldap netlogon query
360 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
362 char addr[INET6_ADDRSTRLEN];
363 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
364 bool ok;
366 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
368 ok = ads_cldap_netlogon_5(
369 talloc_tos(), &ads->ldap.ss, ads->server.realm, 0, &reply);
370 if (!ok) {
371 d_fprintf(stderr, _("CLDAP query failed!\n"));
372 return -1;
375 if (c->opt_json) {
376 return net_ads_cldap_netlogon_json(ads, addr, &reply);
379 d_printf(_("Information for Domain Controller: %s\n\n"),
380 addr);
382 d_printf(_("Response Type: "));
383 switch (reply.command) {
384 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
385 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
386 break;
387 case LOGON_SAM_LOGON_RESPONSE_EX:
388 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
389 break;
390 default:
391 d_printf("0x%x\n", reply.command);
392 break;
395 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
397 d_printf(_("Flags:\n"
398 "\tIs a PDC: %s\n"
399 "\tIs a GC of the forest: %s\n"
400 "\tIs an LDAP server: %s\n"
401 "\tSupports DS: %s\n"
402 "\tIs running a KDC: %s\n"
403 "\tIs running time services: %s\n"
404 "\tIs the closest DC: %s\n"
405 "\tIs writable: %s\n"
406 "\tHas a hardware clock: %s\n"
407 "\tIs a non-domain NC serviced by LDAP server: %s\n"
408 "\tIs NT6 DC that has some secrets: %s\n"
409 "\tIs NT6 DC that has all secrets: %s\n"
410 "\tRuns Active Directory Web Services: %s\n"
411 "\tRuns on Windows 2012 or later: %s\n"
412 "\tRuns on Windows 2012R2 or later: %s\n"
413 "\tRuns on Windows 2016 or later: %s\n"
414 "\tHas a DNS name: %s\n"
415 "\tIs a default NC: %s\n"
416 "\tIs the forest root: %s\n"),
417 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
418 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
419 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
420 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
421 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
422 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
423 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
424 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
425 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
426 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
427 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
428 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"),
429 (reply.server_type & NBT_SERVER_ADS_WEB_SERVICE) ? _("yes") : _("no"),
430 (reply.server_type & NBT_SERVER_DS_8) ? _("yes") : _("no"),
431 (reply.server_type & NBT_SERVER_DS_9) ? _("yes") : _("no"),
432 (reply.server_type & NBT_SERVER_DS_10) ? _("yes") : _("no"),
433 (reply.server_type & NBT_SERVER_HAS_DNS_NAME) ? _("yes") : _("no"),
434 (reply.server_type & NBT_SERVER_IS_DEFAULT_NC) ? _("yes") : _("no"),
435 (reply.server_type & NBT_SERVER_FOREST_ROOT) ? _("yes") : _("no"));
438 printf(_("Forest: %s\n"), reply.forest);
439 printf(_("Domain: %s\n"), reply.dns_domain);
440 printf(_("Domain Controller: %s\n"), reply.pdc_dns_name);
442 printf(_("Pre-Win2k Domain: %s\n"), reply.domain_name);
443 printf(_("Pre-Win2k Hostname: %s\n"), reply.pdc_name);
445 if (*reply.user_name) printf(_("User name: %s\n"), reply.user_name);
447 printf(_("Server Site Name: %s\n"), reply.server_site);
448 printf(_("Client Site Name: %s\n"), reply.client_site);
450 d_printf(_("NT Version: %d\n"), reply.nt_version);
451 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
452 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
454 return 0;
458 this implements the CLDAP based netlogon lookup requests
459 for finding the domain controller of a ADS domain
461 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
463 TALLOC_CTX *tmp_ctx = talloc_stackframe();
464 ADS_STRUCT *ads = NULL;
465 ADS_STATUS status;
466 int ret = -1;
468 if (c->display_usage) {
469 d_printf("%s\n"
470 "net ads lookup\n"
471 " %s",
472 _("Usage:"),
473 _("Find the ADS DC using CLDAP lookup.\n"));
474 TALLOC_FREE(tmp_ctx);
475 return -1;
478 status = ads_startup_nobind(c, false, tmp_ctx, &ads);
479 if (!ADS_ERR_OK(status)) {
480 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
481 goto out;
484 if (!ads->config.realm) {
485 ads->config.realm = talloc_strdup(ads, c->opt_target_workgroup);
486 if (ads->config.realm == NULL) {
487 d_fprintf(stderr, _("Out of memory\n"));
488 goto out;
490 ads->ldap.port = 389;
493 ret = net_ads_cldap_netlogon(c, ads);
494 out:
495 TALLOC_FREE(tmp_ctx);
496 return ret;
500 #ifdef HAVE_JANSSON
502 static int net_ads_info_json(ADS_STRUCT *ads)
504 int ret = 0;
505 char addr[INET6_ADDRSTRLEN];
506 time_t pass_time;
507 struct json_object jsobj = json_new_object();
509 if (json_is_invalid(&jsobj)) {
510 d_fprintf(stderr, _("error setting up JSON value\n"));
512 goto failure;
515 pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
517 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
519 ret = json_add_string (&jsobj, "LDAP server", addr);
520 if (ret != 0) {
521 goto failure;
524 ret = json_add_string (&jsobj, "LDAP server name",
525 ads->config.ldap_server_name);
526 if (ret != 0) {
527 goto failure;
530 ret = json_add_string (&jsobj, "Workgroup", ads->config.workgroup);
531 if (ret != 0) {
532 goto failure;
535 ret = json_add_string (&jsobj, "Realm", ads->config.realm);
536 if (ret != 0) {
537 goto failure;
540 ret = json_add_string (&jsobj, "Bind Path", ads->config.bind_path);
541 if (ret != 0) {
542 goto failure;
545 ret = json_add_int (&jsobj, "LDAP port", ads->ldap.port);
546 if (ret != 0) {
547 goto failure;
550 ret = json_add_int (&jsobj, "Server time", ads->config.current_time);
551 if (ret != 0) {
552 goto failure;
555 ret = json_add_string (&jsobj, "KDC server", ads->auth.kdc_server);
556 if (ret != 0) {
557 goto failure;
560 ret = json_add_int (&jsobj, "Server time offset",
561 ads->config.time_offset);
562 if (ret != 0) {
563 goto failure;
566 ret = json_add_int (&jsobj, "Last machine account password change",
567 pass_time);
568 if (ret != 0) {
569 goto failure;
572 ret = output_json(&jsobj);
573 failure:
574 json_free(&jsobj);
576 return ret;
579 #else /* [HAVE_JANSSON] */
581 static int net_ads_info_json(ADS_STRUCT *ads)
583 d_fprintf(stderr, _("JSON support not available\n"));
585 return -1;
588 #endif /* [HAVE_JANSSON] */
592 static int net_ads_info(struct net_context *c, int argc, const char **argv)
594 TALLOC_CTX *tmp_ctx = talloc_stackframe();
595 ADS_STRUCT *ads = NULL;
596 ADS_STATUS status;
597 char addr[INET6_ADDRSTRLEN];
598 time_t pass_time;
599 int ret = -1;
601 if (c->display_usage) {
602 d_printf("%s\n"
603 "net ads info\n"
604 " %s",
605 _("Usage:"),
606 _("Display information about an Active Directory "
607 "server.\n"));
608 TALLOC_FREE(tmp_ctx);
609 return -1;
612 status = ads_startup_nobind(c, false, tmp_ctx, &ads);
613 if (!ADS_ERR_OK(status)) {
614 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
615 goto out;
618 if (!ads || !ads->config.realm) {
619 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
620 goto out;
623 /* Try to set the server's current time since we didn't do a full
624 TCP LDAP session initially */
626 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
627 d_fprintf( stderr, _("Failed to get server's current time!\n"));
630 if (c->opt_json) {
631 ret = net_ads_info_json(ads);
632 goto out;
635 pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
637 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
639 d_printf(_("LDAP server: %s\n"), addr);
640 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
641 d_printf(_("Workgroup: %s\n"), ads->config.workgroup);
642 d_printf(_("Realm: %s\n"), ads->config.realm);
643 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
644 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
645 d_printf(_("Server time: %s\n"),
646 http_timestring(tmp_ctx, ads->config.current_time));
648 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
649 d_printf(_("Server time offset: %d\n"), ads->config.time_offset );
651 d_printf(_("Last machine account password change: %s\n"),
652 http_timestring(tmp_ctx, pass_time));
654 ret = 0;
655 out:
656 TALLOC_FREE(tmp_ctx);
657 return ret;
660 static ADS_STATUS ads_startup_int(struct net_context *c,
661 bool only_own_domain,
662 uint32_t auth_flags,
663 TALLOC_CTX *mem_ctx,
664 ADS_STRUCT **ads_ret)
666 ADS_STRUCT *ads = NULL;
667 ADS_STATUS status;
668 const char *realm = NULL;
669 const char *workgroup = NULL;
670 bool tried_closest_dc = false;
672 /* lp_realm() should be handled by a command line param,
673 However, the join requires that realm be set in smb.conf
674 and compares our realm with the remote server's so this is
675 ok until someone needs more flexibility */
677 *ads_ret = NULL;
679 retry_connect:
680 if (only_own_domain) {
681 realm = lp_realm();
682 workgroup = lp_workgroup();
683 } else {
684 realm = assume_own_realm(c);
685 workgroup = c->opt_target_workgroup;
688 ads = ads_init(mem_ctx,
689 realm,
690 workgroup,
691 c->opt_host,
692 ADS_SASL_SEAL);
693 if (ads == NULL) {
694 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
697 ads->auth.flags |= auth_flags;
699 if (auth_flags & ADS_AUTH_NO_BIND) {
700 status = ads_connect_cldap_only(ads);
701 if (!ADS_ERR_OK(status)) {
702 DBG_ERR("ads_connect_cldap_only: %s\n",
703 ads_errstr(status));
704 TALLOC_FREE(ads);
705 return status;
707 } else {
708 status = ads_connect_creds(ads, c->creds);
709 if (!ADS_ERR_OK(status)) {
710 DBG_ERR("ads_connect_creds: %s\n",
711 ads_errstr(status));
712 TALLOC_FREE(ads);
713 return status;
717 /* when contacting our own domain, make sure we use the closest DC.
718 * This is done by reconnecting to ADS because only the first call to
719 * ads_connect will give us our own sitename */
721 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
723 tried_closest_dc = true; /* avoid loop */
725 if (!ads_closest_dc(ads)) {
727 namecache_delete(ads->server.realm, 0x1C);
728 namecache_delete(ads->server.workgroup, 0x1C);
730 TALLOC_FREE(ads);
732 goto retry_connect;
736 *ads_ret = talloc_move(mem_ctx, &ads);
737 return status;
740 ADS_STATUS ads_startup(struct net_context *c,
741 bool only_own_domain,
742 TALLOC_CTX *mem_ctx,
743 ADS_STRUCT **ads)
745 return ads_startup_int(c, only_own_domain, 0, mem_ctx, ads);
748 ADS_STATUS ads_startup_nobind(struct net_context *c,
749 bool only_own_domain,
750 TALLOC_CTX *mem_ctx,
751 ADS_STRUCT **ads)
753 return ads_startup_int(c,
754 only_own_domain,
755 ADS_AUTH_NO_BIND,
756 mem_ctx,
757 ads);
761 Check to see if connection can be made via ads.
762 ads_startup() stores the password in opt_password if it needs to so
763 that rpc or rap can use it without re-prompting.
765 static int net_ads_check_int(struct net_context *c,
766 const char *realm,
767 const char *workgroup,
768 const char *host)
770 TALLOC_CTX *tmp_ctx = talloc_stackframe();
771 ADS_STRUCT *ads;
772 ADS_STATUS status;
773 int ret = -1;
775 ads = ads_init(tmp_ctx, realm, workgroup, host, ADS_SASL_PLAIN);
776 if (ads == NULL) {
777 goto out;
780 status = ads_connect_cldap_only(ads);
781 if (!ADS_ERR_OK(status)) {
782 goto out;
785 ret = 0;
786 out:
787 TALLOC_FREE(tmp_ctx);
788 return ret;
791 int net_ads_check_our_domain(struct net_context *c)
793 return net_ads_check_int(c, lp_realm(), lp_workgroup(), NULL);
796 int net_ads_check(struct net_context *c)
798 return net_ads_check_int(c, NULL, c->opt_workgroup, c->opt_host);
802 determine the netbios workgroup name for a domain
804 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
806 TALLOC_CTX *tmp_ctx = talloc_stackframe();
807 ADS_STRUCT *ads = NULL;
808 ADS_STATUS status;
809 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
810 bool ok = false;
811 int ret = -1;
813 if (c->display_usage) {
814 d_printf ("%s\n"
815 "net ads workgroup\n"
816 " %s\n",
817 _("Usage:"),
818 _("Print the workgroup name"));
819 TALLOC_FREE(tmp_ctx);
820 return -1;
823 status = ads_startup_nobind(c, false, tmp_ctx, &ads);
824 if (!ADS_ERR_OK(status)) {
825 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
826 goto out;
829 if (!ads->config.realm) {
830 ads->config.realm = talloc_strdup(ads, c->opt_target_workgroup);
831 if (ads->config.realm == NULL) {
832 d_fprintf(stderr, _("Out of memory\n"));
833 goto out;
835 ads->ldap.port = 389;
838 ok = ads_cldap_netlogon_5(
839 tmp_ctx, &ads->ldap.ss, ads->server.realm, 0, &reply);
840 if (!ok) {
841 d_fprintf(stderr, _("CLDAP query failed!\n"));
842 goto out;
845 d_printf(_("Workgroup: %s\n"), reply.domain_name);
847 ret = 0;
848 out:
849 TALLOC_FREE(tmp_ctx);
851 return ret;
856 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
858 char **disp_fields = (char **) data_area;
860 if (!field) { /* must be end of record */
861 if (disp_fields[0]) {
862 if (!strchr_m(disp_fields[0], '$')) {
863 if (disp_fields[1])
864 d_printf("%-21.21s %s\n",
865 disp_fields[0], disp_fields[1]);
866 else
867 d_printf("%s\n", disp_fields[0]);
870 SAFE_FREE(disp_fields[0]);
871 SAFE_FREE(disp_fields[1]);
872 return true;
874 if (!values) /* must be new field, indicate string field */
875 return true;
876 if (strcasecmp_m(field, "sAMAccountName") == 0) {
877 disp_fields[0] = SMB_STRDUP((char *) values[0]);
879 if (strcasecmp_m(field, "description") == 0)
880 disp_fields[1] = SMB_STRDUP((char *) values[0]);
881 return true;
884 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
886 return net_user_usage(c, argc, argv);
889 static int ads_user_add(struct net_context *c, int argc, const char **argv)
891 TALLOC_CTX *tmp_ctx = talloc_stackframe();
892 ADS_STRUCT *ads = NULL;
893 ADS_STATUS status;
894 char *upn, *userdn;
895 LDAPMessage *res=NULL;
896 char *creds_ccname = NULL;
897 int rc = -1;
898 char *ou_str = NULL;
899 bool ok;
901 if (argc < 1 || c->display_usage) {
902 TALLOC_FREE(tmp_ctx);
903 return net_ads_user_usage(c, argc, argv);
906 if (argc > 1) {
908 * We rely on ads_krb5_set_password() to
909 * set the password below.
911 * We could pass the password to
912 * ads_add_user_acct()
913 * and set the unicodePwd attribute there...
915 cli_credentials_set_kerberos_state(c->creds,
916 CRED_USE_KERBEROS_REQUIRED,
917 CRED_SPECIFIED);
920 status = ads_startup(c, false, tmp_ctx, &ads);
921 if (!ADS_ERR_OK(status)) {
922 goto done;
925 status = ads_find_user_acct(ads, &res, argv[0]);
926 if (!ADS_ERR_OK(status)) {
927 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
928 goto done;
931 if (ads_count_replies(ads, res)) {
932 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
933 argv[0]);
934 goto done;
937 if (c->opt_container) {
938 ou_str = SMB_STRDUP(c->opt_container);
939 } else {
940 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
943 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
944 if (!ADS_ERR_OK(status)) {
945 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
946 ads_errstr(status));
947 goto done;
950 /* if no password is to be set, we're done */
951 if (argc == 1) {
952 d_printf(_("User %s added\n"), argv[0]);
953 rc = 0;
954 goto done;
957 /* try setting the password */
958 upn = talloc_asprintf(tmp_ctx,
959 "%s@%s",
960 argv[0],
961 ads->config.realm);
962 if (upn == NULL) {
963 goto done;
966 ok = cli_credentials_get_ccache_name_obtained(c->creds,
967 tmp_ctx,
968 &creds_ccname,
969 NULL);
970 if (!ok) {
971 d_printf(_("No valid krb5 ccache for: %s\n"),
972 cli_credentials_get_unparsed_name(c->creds, tmp_ctx));
973 goto done;
976 status = ads_krb5_set_password(upn, argv[1], creds_ccname);
977 if (ADS_ERR_OK(status)) {
978 d_printf(_("User %s added\n"), argv[0]);
979 rc = 0;
980 goto done;
982 TALLOC_FREE(upn);
984 /* password didn't set, delete account */
985 d_fprintf(stderr, _("Could not add user %s. "
986 "Error setting password %s\n"),
987 argv[0], ads_errstr(status));
989 ads_msgfree(ads, res);
990 res = NULL;
992 status=ads_find_user_acct(ads, &res, argv[0]);
993 if (ADS_ERR_OK(status)) {
994 userdn = ads_get_dn(ads, tmp_ctx, res);
995 ads_del_dn(ads, userdn);
996 TALLOC_FREE(userdn);
999 done:
1000 ads_msgfree(ads, res);
1001 SAFE_FREE(ou_str);
1002 TALLOC_FREE(tmp_ctx);
1003 return rc;
1006 static int ads_user_info(struct net_context *c, int argc, const char **argv)
1008 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1009 ADS_STRUCT *ads = NULL;
1010 ADS_STATUS status;
1011 LDAPMessage *res = NULL;
1012 int ret = -1;
1013 wbcErr wbc_status;
1014 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
1015 char *searchstring = NULL;
1016 char **grouplist = NULL;
1017 char *primary_group = NULL;
1018 char *escaped_user = NULL;
1019 struct dom_sid primary_group_sid;
1020 uint32_t group_rid;
1021 enum wbcSidType type;
1023 if (argc < 1 || c->display_usage) {
1024 TALLOC_FREE(tmp_ctx);
1025 return net_ads_user_usage(c, argc, argv);
1028 escaped_user = escape_ldap_string(tmp_ctx, argv[0]);
1029 if (!escaped_user) {
1030 d_fprintf(stderr,
1031 _("ads_user_info: failed to escape user %s\n"),
1032 argv[0]);
1033 goto out;
1036 status = ads_startup(c, false, tmp_ctx, &ads);
1037 if (!ADS_ERR_OK(status)) {
1038 goto out;
1041 searchstring = talloc_asprintf(tmp_ctx,
1042 "(sAMAccountName=%s)",
1043 escaped_user);
1044 if (searchstring == NULL) {
1045 goto out;
1048 status = ads_search(ads, &res, searchstring, attrs);
1049 if (!ADS_ERR_OK(status)) {
1050 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(status));
1051 goto out;
1054 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
1055 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
1056 goto out;
1059 status = ads_domain_sid(ads, &primary_group_sid);
1060 if (!ADS_ERR_OK(status)) {
1061 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(status));
1062 goto out;
1065 sid_append_rid(&primary_group_sid, group_rid);
1067 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
1068 NULL, /* don't look up domain */
1069 &primary_group,
1070 &type);
1071 if (!WBC_ERROR_IS_OK(wbc_status)) {
1072 d_fprintf(stderr, "wbcLookupSid: %s\n",
1073 wbcErrorString(wbc_status));
1074 goto out;
1077 d_printf("%s\n", primary_group);
1079 wbcFreeMemory(primary_group);
1081 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
1082 (LDAPMessage *)res, "memberOf");
1084 if (grouplist) {
1085 int i;
1086 char **groupname;
1087 for (i=0;grouplist[i];i++) {
1088 groupname = ldap_explode_dn(grouplist[i], 1);
1089 d_printf("%s\n", groupname[0]);
1090 ldap_value_free(groupname);
1092 ldap_value_free(grouplist);
1095 ret = 0;
1096 out:
1097 TALLOC_FREE(escaped_user);
1098 TALLOC_FREE(searchstring);
1099 ads_msgfree(ads, res);
1100 TALLOC_FREE(tmp_ctx);
1101 return ret;
1104 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
1106 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1107 ADS_STRUCT *ads = NULL;
1108 ADS_STATUS status;
1109 LDAPMessage *res = NULL;
1110 char *userdn = NULL;
1111 int ret = -1;
1113 if (argc < 1) {
1114 TALLOC_FREE(tmp_ctx);
1115 return net_ads_user_usage(c, argc, argv);
1118 status = ads_startup(c, false, tmp_ctx, &ads);
1119 if (!ADS_ERR_OK(status)) {
1120 goto out;
1123 status = ads_find_user_acct(ads, &res, argv[0]);
1124 if (!ADS_ERR_OK(status) || ads_count_replies(ads, res) != 1) {
1125 d_printf(_("User %s does not exist.\n"), argv[0]);
1126 goto out;
1129 userdn = ads_get_dn(ads, tmp_ctx, res);
1130 if (userdn == NULL) {
1131 goto out;
1134 status = ads_del_dn(ads, userdn);
1135 if (!ADS_ERR_OK(status)) {
1136 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
1137 ads_errstr(status));
1138 goto out;
1141 d_printf(_("User %s deleted\n"), argv[0]);
1143 ret = 0;
1144 out:
1145 ads_msgfree(ads, res);
1146 TALLOC_FREE(tmp_ctx);
1147 return ret;
1150 int net_ads_user(struct net_context *c, int argc, const char **argv)
1152 struct functable func[] = {
1154 "add",
1155 ads_user_add,
1156 NET_TRANSPORT_ADS,
1157 N_("Add an AD user"),
1158 N_("net ads user add\n"
1159 " Add an AD user")
1162 "info",
1163 ads_user_info,
1164 NET_TRANSPORT_ADS,
1165 N_("Display information about an AD user"),
1166 N_("net ads user info\n"
1167 " Display information about an AD user")
1170 "delete",
1171 ads_user_delete,
1172 NET_TRANSPORT_ADS,
1173 N_("Delete an AD user"),
1174 N_("net ads user delete\n"
1175 " Delete an AD user")
1177 {NULL, NULL, 0, NULL, NULL}
1179 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1180 ADS_STRUCT *ads = NULL;
1181 ADS_STATUS status;
1182 const char *shortattrs[] = {"sAMAccountName", NULL};
1183 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1184 char *disp_fields[2] = {NULL, NULL};
1185 int ret = -1;
1187 if (argc > 0) {
1188 TALLOC_FREE(tmp_ctx);
1189 return net_run_function(c, argc, argv, "net ads user", func);
1192 if (c->display_usage) {
1193 d_printf( "%s\n"
1194 "net ads user\n"
1195 " %s\n",
1196 _("Usage:"),
1197 _("List AD users"));
1198 net_display_usage_from_functable(func);
1199 TALLOC_FREE(tmp_ctx);
1200 return -1;
1203 status = ads_startup(c, false, tmp_ctx, &ads);
1204 if (!ADS_ERR_OK(status)) {
1205 goto out;
1208 if (c->opt_long_list_entries)
1209 d_printf(_("\nUser name Comment"
1210 "\n-----------------------------\n"));
1212 status = ads_do_search_all_fn(ads,
1213 ads->config.bind_path,
1214 LDAP_SCOPE_SUBTREE,
1215 "(objectCategory=user)",
1216 c->opt_long_list_entries ?
1217 longattrs : shortattrs,
1218 usergrp_display,
1219 disp_fields);
1220 if (!ADS_ERR_OK(status)) {
1221 goto out;
1224 ret = 0;
1225 out:
1226 TALLOC_FREE(tmp_ctx);
1227 return ret;
1230 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
1232 return net_group_usage(c, argc, argv);
1235 static int ads_group_add(struct net_context *c, int argc, const char **argv)
1237 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1238 ADS_STRUCT *ads = NULL;
1239 ADS_STATUS status;
1240 LDAPMessage *res = NULL;
1241 int ret = -1;
1242 char *ou_str = NULL;
1244 if (argc < 1 || c->display_usage) {
1245 TALLOC_FREE(tmp_ctx);
1246 return net_ads_group_usage(c, argc, argv);
1249 status = ads_startup(c, false, tmp_ctx, &ads);
1250 if (!ADS_ERR_OK(status)) {
1251 goto out;
1254 status = ads_find_user_acct(ads, &res, argv[0]);
1255 if (!ADS_ERR_OK(status)) {
1256 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
1257 goto out;
1260 if (ads_count_replies(ads, res)) {
1261 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
1262 goto out;
1265 if (c->opt_container) {
1266 ou_str = SMB_STRDUP(c->opt_container);
1267 } else {
1268 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
1271 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
1272 if (!ADS_ERR_OK(status)) {
1273 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
1274 ads_errstr(status));
1275 goto out;
1278 d_printf(_("Group %s added\n"), argv[0]);
1280 ret = 0;
1281 out:
1282 ads_msgfree(ads, res);
1283 SAFE_FREE(ou_str);
1284 TALLOC_FREE(tmp_ctx);
1285 return ret;
1288 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
1290 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1291 ADS_STRUCT *ads = NULL;
1292 ADS_STATUS status;
1293 LDAPMessage *res = NULL;
1294 char *groupdn = NULL;
1295 int ret = -1;
1297 if (argc < 1 || c->display_usage) {
1298 TALLOC_FREE(tmp_ctx);
1299 return net_ads_group_usage(c, argc, argv);
1302 status = ads_startup(c, false, tmp_ctx, &ads);
1303 if (!ADS_ERR_OK(status)) {
1304 goto out;
1307 status = ads_find_user_acct(ads, &res, argv[0]);
1308 if (!ADS_ERR_OK(status) || ads_count_replies(ads, res) != 1) {
1309 d_printf(_("Group %s does not exist.\n"), argv[0]);
1310 goto out;
1313 groupdn = ads_get_dn(ads, tmp_ctx, res);
1314 if (groupdn == NULL) {
1315 goto out;
1318 status = ads_del_dn(ads, groupdn);
1319 if (!ADS_ERR_OK(status)) {
1320 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
1321 ads_errstr(status));
1322 goto out;
1324 d_printf(_("Group %s deleted\n"), argv[0]);
1326 ret = 0;
1327 out:
1328 ads_msgfree(ads, res);
1329 TALLOC_FREE(tmp_ctx);
1330 return ret;
1333 int net_ads_group(struct net_context *c, int argc, const char **argv)
1335 struct functable func[] = {
1337 "add",
1338 ads_group_add,
1339 NET_TRANSPORT_ADS,
1340 N_("Add an AD group"),
1341 N_("net ads group add\n"
1342 " Add an AD group")
1345 "delete",
1346 ads_group_delete,
1347 NET_TRANSPORT_ADS,
1348 N_("Delete an AD group"),
1349 N_("net ads group delete\n"
1350 " Delete an AD group")
1352 {NULL, NULL, 0, NULL, NULL}
1354 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1355 ADS_STRUCT *ads = NULL;
1356 ADS_STATUS status;
1357 const char *shortattrs[] = {"sAMAccountName", NULL};
1358 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1359 char *disp_fields[2] = {NULL, NULL};
1360 int ret = -1;
1362 if (argc >= 0) {
1363 TALLOC_FREE(tmp_ctx);
1364 return net_run_function(c, argc, argv, "net ads group", func);
1367 if (c->display_usage) {
1368 d_printf( "%s\n"
1369 "net ads group\n"
1370 " %s\n",
1371 _("Usage:"),
1372 _("List AD groups"));
1373 net_display_usage_from_functable(func);
1374 TALLOC_FREE(tmp_ctx);
1375 return -1;
1378 status = ads_startup(c, false, tmp_ctx, &ads);
1379 if (!ADS_ERR_OK(status)) {
1380 goto out;
1383 if (c->opt_long_list_entries)
1384 d_printf(_("\nGroup name Comment"
1385 "\n-----------------------------\n"));
1387 status = ads_do_search_all_fn(ads,
1388 ads->config.bind_path,
1389 LDAP_SCOPE_SUBTREE,
1390 "(objectCategory=group)",
1391 c->opt_long_list_entries ?
1392 longattrs : shortattrs,
1393 usergrp_display,
1394 disp_fields);
1395 if (!ADS_ERR_OK(status)) {
1396 goto out;
1399 ret = 0;
1400 out:
1401 TALLOC_FREE(tmp_ctx);
1402 return ret;
1405 static int net_ads_status(struct net_context *c, int argc, const char **argv)
1407 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1408 ADS_STRUCT *ads = NULL;
1409 ADS_STATUS status;
1410 LDAPMessage *res = NULL;
1411 int ret = -1;
1413 if (c->display_usage) {
1414 d_printf( "%s\n"
1415 "net ads status\n"
1416 " %s\n",
1417 _("Usage:"),
1418 _("Display machine account details"));
1419 TALLOC_FREE(tmp_ctx);
1420 return -1;
1423 net_warn_member_options();
1425 status = ads_startup(c, true, tmp_ctx, &ads);
1426 if (!ADS_ERR_OK(status)) {
1427 goto out;
1430 status = ads_find_machine_acct(ads, &res, lp_netbios_name());
1431 if (!ADS_ERR_OK(status)) {
1432 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"),
1433 ads_errstr(status));
1434 goto out;
1437 if (ads_count_replies(ads, res) == 0) {
1438 d_fprintf(stderr, _("No machine account for '%s' found\n"),
1439 lp_netbios_name());
1440 goto out;
1443 ads_dump(ads, res);
1445 ret = 0;
1446 out:
1447 ads_msgfree(ads, res);
1448 TALLOC_FREE(tmp_ctx);
1449 return ret;
1452 /*******************************************************************
1453 Leave an AD domain. Windows XP disables the machine account.
1454 We'll try the same. The old code would do an LDAP delete.
1455 That only worked using the machine creds because added the machine
1456 with full control to the computer object's ACL.
1457 *******************************************************************/
1459 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
1461 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1462 struct libnet_UnjoinCtx *r = NULL;
1463 WERROR werr;
1464 int ret = -1;
1466 if (c->display_usage) {
1467 d_printf( "%s\n"
1468 "net ads leave [--keep-account]\n"
1469 " %s\n",
1470 _("Usage:"),
1471 _("Leave an AD domain"));
1472 TALLOC_FREE(tmp_ctx);
1473 return -1;
1476 if (!*lp_realm()) {
1477 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
1478 TALLOC_FREE(tmp_ctx);
1479 return -1;
1482 if (!c->msg_ctx) {
1483 d_fprintf(stderr, _("Could not initialise message context. "
1484 "Try running as root\n"));
1485 goto done;
1488 werr = libnet_init_UnjoinCtx(tmp_ctx, &r);
1489 if (!W_ERROR_IS_OK(werr)) {
1490 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
1491 goto done;
1494 r->in.debug = true;
1495 r->in.dc_name = c->opt_host;
1496 r->in.domain_name = lp_dnsdomain();
1497 r->in.admin_credentials = c->creds;
1498 r->in.modify_config = lp_config_backend_is_registry();
1500 /* Try to delete it, but if that fails, disable it. The
1501 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1502 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1503 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1504 if (c->opt_keep_account) {
1505 r->in.delete_machine_account = false;
1506 } else {
1507 r->in.delete_machine_account = true;
1510 r->in.msg_ctx = c->msg_ctx;
1512 werr = libnet_Unjoin(tmp_ctx, r);
1513 if (!W_ERROR_IS_OK(werr)) {
1514 d_printf(_("Failed to leave domain: %s\n"),
1515 r->out.error_string ? r->out.error_string :
1516 get_friendly_werror_msg(werr));
1517 goto done;
1520 if (r->out.deleted_machine_account) {
1521 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1522 r->in.machine_name, r->out.dns_domain_name);
1523 ret = 0;
1524 goto done;
1527 /* We couldn't delete it - see if the disable succeeded. */
1528 if (r->out.disabled_machine_account) {
1529 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1530 r->in.machine_name, r->out.dns_domain_name);
1531 ret = 0;
1532 goto done;
1535 /* Based on what we requested, we shouldn't get here, but if
1536 we did, it means the secrets were removed, and therefore
1537 we have left the domain */
1538 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1539 r->in.machine_name, r->out.dns_domain_name);
1541 ret = 0;
1542 done:
1543 TALLOC_FREE(tmp_ctx);
1544 return ret;
1547 static ADS_STATUS net_ads_join_ok(struct net_context *c)
1549 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1550 ADS_STRUCT *ads = NULL;
1551 ADS_STATUS status;
1552 fstring dc_name;
1553 struct sockaddr_storage dcip;
1555 if (!secrets_init()) {
1556 DEBUG(1,("Failed to initialise secrets database\n"));
1557 TALLOC_FREE(tmp_ctx);
1558 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
1561 net_warn_member_options();
1563 net_use_krb_machine_account(c);
1565 if (!cli_credentials_authentication_requested(c->creds)) {
1566 DBG_ERR("Failed to get machine credentials\n");
1567 TALLOC_FREE(tmp_ctx);
1568 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
1571 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1573 status = ads_startup(c, true, tmp_ctx, &ads);
1574 if (!ADS_ERR_OK(status)) {
1575 goto out;
1578 status = ADS_ERROR_NT(NT_STATUS_OK);
1579 out:
1580 TALLOC_FREE(tmp_ctx);
1581 return status;
1585 check that an existing join is OK
1587 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1589 ADS_STATUS status;
1591 if (c->display_usage) {
1592 d_printf( "%s\n"
1593 "net ads testjoin\n"
1594 " %s\n",
1595 _("Usage:"),
1596 _("Test if the existing join is ok"));
1597 return -1;
1600 net_warn_member_options();
1602 /* Display success or failure */
1603 status = net_ads_join_ok(c);
1604 if (!ADS_ERR_OK(status)) {
1605 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1606 get_friendly_nt_error_msg(ads_ntstatus(status)));
1607 return -1;
1610 printf(_("Join is OK\n"));
1611 return 0;
1614 /*******************************************************************
1615 Simple config checks before beginning the join
1616 ********************************************************************/
1618 static WERROR check_ads_config( void )
1620 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1621 d_printf(_("Host is not configured as a member server.\n"));
1622 return WERR_INVALID_DOMAIN_ROLE;
1625 if (strlen(lp_netbios_name()) > 15) {
1626 d_printf(_("Our netbios name can be at most 15 chars long, "
1627 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1628 (unsigned int)strlen(lp_netbios_name()));
1629 return WERR_INVALID_COMPUTERNAME;
1632 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1633 d_fprintf(stderr, _("realm must be set in %s for ADS "
1634 "join to succeed.\n"), get_dyn_CONFIGFILE());
1635 return WERR_INVALID_PARAMETER;
1638 return WERR_OK;
1641 /*******************************************************************
1642 ********************************************************************/
1644 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1646 d_printf(_("net ads join [--no-dns-updates] [options]\n"
1647 "Valid options:\n"));
1648 d_printf(_(" dnshostname=FQDN Set the dnsHostName attribute during the join.\n"
1649 " The default is in the form netbiosname.dnsdomain\n"));
1650 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1651 " The default UPN is in the form host/netbiosname@REALM.\n"));
1652 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1653 " The OU string read from top to bottom without RDNs\n"
1654 " and delimited by a '/'.\n"
1655 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1656 " NB: A backslash '\\' is used as escape at multiple\n"
1657 " levels and may need to be doubled or even\n"
1658 " quadrupled. It is not used as a separator.\n"));
1659 d_printf(_(" machinepass=PASS Set the machine password to a specific value during\n"
1660 " the join. The default password is random.\n"));
1661 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1662 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during join.\n"
1663 " NB: osName and osVer must be specified together for\n"
1664 " either to take effect. The operatingSystemService\n"
1665 " attribute is then also set along with the two\n"
1666 " other attributes.\n"));
1667 d_printf(_(" osServicePack=string Set the operatingSystemServicePack attribute\n"
1668 " during the join.\n"
1669 " NB: If not specified then by default the samba\n"
1670 " version string is used instead.\n"));
1671 return -1;
1675 int net_ads_join(struct net_context *c, int argc, const char **argv)
1677 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1678 struct libnet_JoinCtx *r = NULL;
1679 const char *domain = lp_realm();
1680 WERROR werr = WERR_NERR_SETUPNOTJOINED;
1681 bool createupn = false;
1682 const char *dnshostname = NULL;
1683 const char *machineupn = NULL;
1684 const char *machine_password = NULL;
1685 const char *create_in_ou = NULL;
1686 int i;
1687 const char *os_name = NULL;
1688 const char *os_version = NULL;
1689 const char *os_servicepack = NULL;
1690 bool modify_config = lp_config_backend_is_registry();
1691 enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1692 int ret = -1;
1694 if (c->display_usage) {
1695 TALLOC_FREE(tmp_ctx);
1696 return net_ads_join_usage(c, argc, argv);
1699 net_warn_member_options();
1701 if (!modify_config) {
1702 werr = check_ads_config();
1703 if (!W_ERROR_IS_OK(werr)) {
1704 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1705 goto fail;
1709 werr = libnet_init_JoinCtx(tmp_ctx, &r);
1710 if (!W_ERROR_IS_OK(werr)) {
1711 goto fail;
1714 /* process additional command line args */
1716 for ( i=0; i<argc; i++ ) {
1717 if ( !strncasecmp_m(argv[i], "dnshostname", strlen("dnshostname")) ) {
1718 dnshostname = get_string_param(argv[i]);
1720 else if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1721 createupn = true;
1722 machineupn = get_string_param(argv[i]);
1724 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1725 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1726 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1727 werr = WERR_INVALID_PARAMETER;
1728 goto fail;
1731 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1732 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1733 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1734 werr = WERR_INVALID_PARAMETER;
1735 goto fail;
1738 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1739 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1740 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1741 werr = WERR_INVALID_PARAMETER;
1742 goto fail;
1745 else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1746 if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1747 d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1748 werr = WERR_INVALID_PARAMETER;
1749 goto fail;
1752 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1753 if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1754 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1755 werr = WERR_INVALID_PARAMETER;
1756 goto fail;
1758 } else {
1759 domain = argv[i];
1760 if (strchr(domain, '.') == NULL) {
1761 domain_name_type = JoinDomNameTypeUnknown;
1762 } else {
1763 domain_name_type = JoinDomNameTypeDNS;
1768 if (!*domain) {
1769 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1770 werr = WERR_INVALID_PARAMETER;
1771 goto fail;
1774 if (!c->msg_ctx) {
1775 d_fprintf(stderr, _("Could not initialise message context. "
1776 "Try running as root\n"));
1777 werr = WERR_ACCESS_DENIED;
1778 goto fail;
1781 /* Do the domain join here */
1783 r->in.domain_name = domain;
1784 r->in.domain_name_type = domain_name_type;
1785 r->in.create_upn = createupn;
1786 r->in.upn = machineupn;
1787 r->in.dnshostname = dnshostname;
1788 r->in.account_ou = create_in_ou;
1789 r->in.os_name = os_name;
1790 r->in.os_version = os_version;
1791 r->in.os_servicepack = os_servicepack;
1792 r->in.dc_name = c->opt_host;
1793 r->in.admin_credentials = c->creds;
1794 r->in.machine_password = machine_password;
1795 r->in.debug = true;
1796 r->in.modify_config = modify_config;
1797 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1798 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1799 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1800 r->in.msg_ctx = c->msg_ctx;
1802 werr = libnet_Join(tmp_ctx, r);
1803 if (W_ERROR_EQUAL(werr, WERR_NERR_DCNOTFOUND) &&
1804 strequal(domain, lp_realm())) {
1805 r->in.domain_name = lp_workgroup();
1806 r->in.domain_name_type = JoinDomNameTypeNBT;
1807 werr = libnet_Join(tmp_ctx, r);
1809 if (!W_ERROR_IS_OK(werr)) {
1810 goto fail;
1813 /* Check the short name of the domain */
1815 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1816 d_printf(_("The workgroup in %s does not match the short\n"
1817 "domain name obtained from the server.\n"
1818 "Using the name [%s] from the server.\n"
1819 "You should set \"workgroup = %s\" in %s.\n"),
1820 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1821 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1824 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1826 if (r->out.dns_domain_name) {
1827 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1828 r->out.dns_domain_name);
1829 } else {
1830 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1831 r->out.netbios_domain_name);
1834 /* print out informative error string in case there is one */
1835 if (r->out.error_string != NULL) {
1836 d_printf("%s\n", r->out.error_string);
1840 * We try doing the dns update (if it was compiled in
1841 * and if it was not disabled on the command line).
1842 * If the dns update fails, we still consider the join
1843 * operation as succeeded if we came this far.
1845 if (!c->opt_no_dns_updates) {
1846 net_ads_join_dns_updates(c, tmp_ctx, r);
1849 ret = 0;
1851 fail:
1852 if (ret != 0) {
1853 /* issue an overall failure message at the end. */
1854 d_printf(_("Failed to join domain: %s\n"),
1855 r && r->out.error_string ? r->out.error_string :
1856 get_friendly_werror_msg(werr));
1859 TALLOC_FREE(tmp_ctx);
1861 return ret;
1864 /*******************************************************************
1865 ********************************************************************/
1867 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1869 #if defined(HAVE_KRB5)
1870 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1871 ADS_STRUCT *ads = NULL;
1872 ADS_STATUS status;
1873 NTSTATUS ntstatus;
1874 const char *hostname = NULL;
1875 const char **addrs_list = NULL;
1876 struct sockaddr_storage *addrs = NULL;
1877 int num_addrs = 0;
1878 int count;
1879 int ret = -1;
1881 #ifdef DEVELOPER
1882 talloc_enable_leak_report();
1883 #endif
1885 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1886 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1887 "detection of addresses in a clustered "
1888 "setup.\n"));
1889 c->display_usage = true;
1892 if (c->display_usage) {
1893 d_printf( "%s\n"
1894 "net ads dns register [hostname [IP [IP...]]] "
1895 "[--force] [--dns-ttl TTL]\n"
1896 " %s\n",
1897 _("Usage:"),
1898 _("Register hostname with DNS\n"));
1899 TALLOC_FREE(tmp_ctx);
1900 return -1;
1903 if (argc >= 1) {
1904 hostname = argv[0];
1907 if (argc > 1) {
1908 num_addrs = argc - 1;
1909 addrs_list = &argv[1];
1910 } else if (lp_clustering()) {
1911 addrs_list = lp_cluster_addresses();
1912 num_addrs = str_list_length(addrs_list);
1915 if (num_addrs > 0) {
1916 addrs = talloc_zero_array(tmp_ctx,
1917 struct sockaddr_storage,
1918 num_addrs);
1919 if (addrs == NULL) {
1920 d_fprintf(stderr, _("Error allocating memory!\n"));
1921 goto out;
1925 for (count = 0; count < num_addrs; count++) {
1926 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1927 d_fprintf(stderr, "%s '%s'.\n",
1928 _("Cannot interpret address"),
1929 addrs_list[count]);
1930 goto out;
1934 status = ads_startup(c, true, tmp_ctx, &ads);
1935 if ( !ADS_ERR_OK(status) ) {
1936 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1937 goto out;
1940 ntstatus = net_update_dns_ext(c,
1941 tmp_ctx,
1942 ads,
1943 c->creds,
1944 hostname,
1945 addrs,
1946 num_addrs,
1947 false);
1948 if (!NT_STATUS_IS_OK(ntstatus)) {
1949 d_fprintf( stderr, _("DNS update failed!\n") );
1950 goto out;
1953 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1955 ret = 0;
1956 out:
1957 TALLOC_FREE(tmp_ctx);
1959 return ret;
1960 #else
1961 d_fprintf(stderr,
1962 _("DNS update support not enabled at compile time!\n"));
1963 return -1;
1964 #endif
1967 static int net_ads_dns_unregister(struct net_context *c,
1968 int argc,
1969 const char **argv)
1971 #if defined(HAVE_KRB5)
1972 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1973 ADS_STRUCT *ads = NULL;
1974 ADS_STATUS status;
1975 NTSTATUS ntstatus;
1976 const char *hostname = NULL;
1977 int ret = -1;
1979 #ifdef DEVELOPER
1980 talloc_enable_leak_report();
1981 #endif
1983 if (argc != 1) {
1984 c->display_usage = true;
1987 if (c->display_usage) {
1988 d_printf( "%s\n"
1989 "net ads dns unregister [hostname]\n"
1990 " %s\n",
1991 _("Usage:"),
1992 _("Remove all IP Address entries for a given\n"
1993 " hostname from the Active Directory server.\n"));
1994 TALLOC_FREE(tmp_ctx);
1995 return -1;
1998 /* Get the hostname for un-registering */
1999 hostname = argv[0];
2001 status = ads_startup(c, true, tmp_ctx, &ads);
2002 if ( !ADS_ERR_OK(status) ) {
2003 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
2004 goto out;
2007 ntstatus = net_update_dns_ext(c,
2008 tmp_ctx,
2009 ads,
2010 c->creds,
2011 hostname,
2012 NULL,
2014 true);
2015 if (!NT_STATUS_IS_OK(ntstatus)) {
2016 d_fprintf( stderr, _("DNS update failed!\n") );
2017 goto out;
2020 d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
2022 ret = 0;
2023 out:
2024 TALLOC_FREE(tmp_ctx);
2026 return ret;
2027 #else
2028 d_fprintf(stderr,
2029 _("DNS update support not enabled at compile time!\n"));
2030 return -1;
2031 #endif
2035 static int net_ads_dns_async(struct net_context *c, int argc, const char **argv)
2037 size_t num_names = 0;
2038 char **hostnames = NULL;
2039 size_t i = 0;
2040 struct samba_sockaddr *addrs = NULL;
2041 NTSTATUS status;
2043 if (argc != 1 || c->display_usage) {
2044 d_printf( "%s\n"
2045 " %s\n"
2046 " %s\n",
2047 _("Usage:"),
2048 _("net ads dns async <name>\n"),
2049 _(" Async look up hostname from the DNS server\n"
2050 " hostname\tName to look up\n"));
2051 return -1;
2054 status = ads_dns_lookup_a(talloc_tos(),
2055 argv[0],
2056 &num_names,
2057 &hostnames,
2058 &addrs);
2059 if (!NT_STATUS_IS_OK(status)) {
2060 d_printf("Looking up A record for %s got error %s\n",
2061 argv[0],
2062 nt_errstr(status));
2063 return -1;
2065 d_printf("Async A record lookup - got %u names for %s\n",
2066 (unsigned int)num_names,
2067 argv[0]);
2068 for (i = 0; i < num_names; i++) {
2069 char addr_buf[INET6_ADDRSTRLEN];
2070 print_sockaddr(addr_buf,
2071 sizeof(addr_buf),
2072 &addrs[i].u.ss);
2073 d_printf("hostname[%u] = %s, IPv4addr = %s\n",
2074 (unsigned int)i,
2075 hostnames[i],
2076 addr_buf);
2079 #if defined(HAVE_IPV6)
2080 status = ads_dns_lookup_aaaa(talloc_tos(),
2081 argv[0],
2082 &num_names,
2083 &hostnames,
2084 &addrs);
2085 if (!NT_STATUS_IS_OK(status)) {
2086 d_printf("Looking up AAAA record for %s got error %s\n",
2087 argv[0],
2088 nt_errstr(status));
2089 return -1;
2091 d_printf("Async AAAA record lookup - got %u names for %s\n",
2092 (unsigned int)num_names,
2093 argv[0]);
2094 for (i = 0; i < num_names; i++) {
2095 char addr_buf[INET6_ADDRSTRLEN];
2096 print_sockaddr(addr_buf,
2097 sizeof(addr_buf),
2098 &addrs[i].u.ss);
2099 d_printf("hostname[%u] = %s, IPv6addr = %s\n",
2100 (unsigned int)i,
2101 hostnames[i],
2102 addr_buf);
2104 #endif
2105 return 0;
2109 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
2111 struct functable func[] = {
2113 "register",
2114 net_ads_dns_register,
2115 NET_TRANSPORT_ADS,
2116 N_("Add FQDN dns entry to AD"),
2117 N_("net ads dns register [FQDN [IP [IP.....]]]\n"
2118 " Add FQDN dns entry to AD")
2121 "unregister",
2122 net_ads_dns_unregister,
2123 NET_TRANSPORT_ADS,
2124 N_("Remove FQDN dns entry from AD"),
2125 N_("net ads dns unregister <FQDN>\n"
2126 " Remove FQDN dns entry from AD")
2129 "async",
2130 net_ads_dns_async,
2131 NET_TRANSPORT_ADS,
2132 N_("Look up host"),
2133 N_("net ads dns async\n"
2134 " Look up host using async DNS")
2136 {NULL, NULL, 0, NULL, NULL}
2139 return net_run_function(c, argc, argv, "net ads dns", func);
2142 /*******************************************************************
2143 ********************************************************************/
2145 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
2147 d_printf(_(
2148 "\nnet ads printer search <printer>"
2149 "\n\tsearch for a printer in the directory\n"
2150 "\nnet ads printer info <printer> <server>"
2151 "\n\tlookup info in directory for printer on server"
2152 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2153 "\nnet ads printer publish <printername>"
2154 "\n\tpublish printer in directory"
2155 "\n\t(note: printer name is required)\n"
2156 "\nnet ads printer remove <printername>"
2157 "\n\tremove printer from directory"
2158 "\n\t(note: printer name is required)\n"));
2159 return -1;
2162 /*******************************************************************
2163 ********************************************************************/
2165 static int net_ads_printer_search(struct net_context *c,
2166 int argc,
2167 const char **argv)
2169 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2170 ADS_STRUCT *ads = NULL;
2171 ADS_STATUS status;
2172 LDAPMessage *res = NULL;
2173 int ret = -1;
2175 if (c->display_usage) {
2176 d_printf( "%s\n"
2177 "net ads printer search\n"
2178 " %s\n",
2179 _("Usage:"),
2180 _("List printers in the AD"));
2181 TALLOC_FREE(tmp_ctx);
2182 return -1;
2185 status = ads_startup(c, false, tmp_ctx, &ads);
2186 if (!ADS_ERR_OK(status)) {
2187 goto out;
2190 status = ads_find_printers(ads, &res);
2191 if (!ADS_ERR_OK(status)) {
2192 d_fprintf(stderr, _("ads_find_printer: %s\n"),
2193 ads_errstr(status));
2194 goto out;
2197 if (ads_count_replies(ads, res) == 0) {
2198 d_fprintf(stderr, _("No results found\n"));
2199 goto out;
2202 ads_dump(ads, res);
2204 ret = 0;
2205 out:
2206 ads_msgfree(ads, res);
2207 TALLOC_FREE(tmp_ctx);
2208 return ret;
2211 static int net_ads_printer_info(struct net_context *c,
2212 int argc,
2213 const char **argv)
2215 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2216 ADS_STRUCT *ads = NULL;
2217 ADS_STATUS status;
2218 const char *servername = NULL;
2219 const char *printername = NULL;
2220 LDAPMessage *res = NULL;
2221 int ret = -1;
2223 if (c->display_usage) {
2224 d_printf("%s\n%s",
2225 _("Usage:"),
2226 _("net ads printer info [printername [servername]]\n"
2227 " Display printer info from AD\n"
2228 " printername\tPrinter name or wildcard\n"
2229 " servername\tName of the print server\n"));
2230 TALLOC_FREE(tmp_ctx);
2231 return -1;
2234 status = ads_startup(c, false, tmp_ctx, &ads);
2235 if (!ADS_ERR_OK(status)) {
2236 goto out;
2239 if (argc > 0) {
2240 printername = argv[0];
2241 } else {
2242 printername = "*";
2245 if (argc > 1) {
2246 servername = argv[1];
2247 } else {
2248 servername = lp_netbios_name();
2251 status = ads_find_printer_on_server(ads, &res, printername, servername);
2252 if (!ADS_ERR_OK(status)) {
2253 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
2254 servername, ads_errstr(status));
2255 goto out;
2258 if (ads_count_replies(ads, res) == 0) {
2259 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
2260 goto out;
2263 ads_dump(ads, res);
2265 ret = 0;
2266 out:
2267 ads_msgfree(ads, res);
2268 TALLOC_FREE(tmp_ctx);
2269 return ret;
2272 static int net_ads_printer_publish(struct net_context *c,
2273 int argc,
2274 const char **argv)
2276 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2277 ADS_STRUCT *ads = NULL;
2278 ADS_STATUS status;
2279 const char *servername = NULL;
2280 const char *printername = NULL;
2281 struct cli_state *cli = NULL;
2282 struct rpc_pipe_client *pipe_hnd = NULL;
2283 struct sockaddr_storage server_ss = { 0 };
2284 NTSTATUS nt_status;
2285 ADS_MODLIST mods = NULL;
2286 char *prt_dn = NULL;
2287 char *srv_dn = NULL;
2288 char **srv_cn = NULL;
2289 char *srv_cn_escaped = NULL;
2290 char *printername_escaped = NULL;
2291 LDAPMessage *res = NULL;
2292 bool ok;
2293 int ret = -1;
2295 if (argc < 1 || c->display_usage) {
2296 d_printf("%s\n%s",
2297 _("Usage:"),
2298 _("net ads printer publish <printername> [servername]\n"
2299 " Publish printer in AD\n"
2300 " printername\tName of the printer\n"
2301 " servername\tName of the print server\n"));
2302 TALLOC_FREE(tmp_ctx);
2303 return -1;
2306 mods = ads_init_mods(tmp_ctx);
2307 if (mods == NULL) {
2308 d_fprintf(stderr, _("Out of memory\n"));
2309 goto out;
2312 status = ads_startup(c, true, tmp_ctx, &ads);
2313 if (!ADS_ERR_OK(status)) {
2314 goto out;
2317 printername = argv[0];
2319 if (argc == 2) {
2320 servername = argv[1];
2321 } else {
2322 servername = lp_netbios_name();
2325 /* Get printer data from SPOOLSS */
2327 ok = resolve_name(servername, &server_ss, 0x20, false);
2328 if (!ok) {
2329 d_fprintf(stderr, _("Could not find server %s\n"),
2330 servername);
2331 goto out;
2334 cli_credentials_set_kerberos_state(c->creds,
2335 CRED_USE_KERBEROS_REQUIRED,
2336 CRED_SPECIFIED);
2338 nt_status = cli_full_connection_creds(c,
2339 &cli,
2340 lp_netbios_name(),
2341 servername,
2342 &server_ss,
2344 "IPC$",
2345 "IPC",
2346 c->creds,
2347 CLI_FULL_CONNECTION_IPC);
2349 if (NT_STATUS_IS_ERR(nt_status)) {
2350 d_fprintf(stderr, _("Unable to open a connection to %s to "
2351 "obtain data for %s\n"),
2352 servername, printername);
2353 goto out;
2356 /* Publish on AD server */
2358 ads_find_machine_acct(ads, &res, servername);
2360 if (ads_count_replies(ads, res) == 0) {
2361 d_fprintf(stderr, _("Could not find machine account for server "
2362 "%s\n"),
2363 servername);
2364 goto out;
2367 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2368 srv_cn = ldap_explode_dn(srv_dn, 1);
2370 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2371 printername_escaped = escape_rdn_val_string_alloc(printername);
2372 if (!srv_cn_escaped || !printername_escaped) {
2373 SAFE_FREE(srv_cn_escaped);
2374 SAFE_FREE(printername_escaped);
2375 d_fprintf(stderr, _("Internal error, out of memory!"));
2376 goto out;
2379 prt_dn = talloc_asprintf(tmp_ctx,
2380 "cn=%s-%s,%s",
2381 srv_cn_escaped,
2382 printername_escaped,
2383 srv_dn);
2384 if (prt_dn == NULL) {
2385 SAFE_FREE(srv_cn_escaped);
2386 SAFE_FREE(printername_escaped);
2387 d_fprintf(stderr, _("Internal error, out of memory!"));
2388 goto out;
2391 SAFE_FREE(srv_cn_escaped);
2392 SAFE_FREE(printername_escaped);
2394 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2395 if (!NT_STATUS_IS_OK(nt_status)) {
2396 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2397 servername);
2398 goto out;
2401 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd,
2402 tmp_ctx,
2403 &mods,
2404 printername))) {
2405 goto out;
2408 status = ads_add_printer_entry(ads, prt_dn, tmp_ctx, &mods);
2409 if (!ADS_ERR_OK(status)) {
2410 d_fprintf(stderr, "ads_publish_printer: %s\n",
2411 ads_errstr(status));
2412 goto out;
2415 d_printf("published printer\n");
2417 ret = 0;
2418 out:
2419 talloc_destroy(tmp_ctx);
2421 return ret;
2424 static int net_ads_printer_remove(struct net_context *c,
2425 int argc,
2426 const char **argv)
2428 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2429 ADS_STRUCT *ads = NULL;
2430 ADS_STATUS status;
2431 const char *servername = NULL;
2432 char *prt_dn = NULL;
2433 LDAPMessage *res = NULL;
2434 int ret = -1;
2436 if (argc < 1 || c->display_usage) {
2437 d_printf("%s\n%s",
2438 _("Usage:"),
2439 _("net ads printer remove <printername> [servername]\n"
2440 " Remove a printer from the AD\n"
2441 " printername\tName of the printer\n"
2442 " servername\tName of the print server\n"));
2443 TALLOC_FREE(tmp_ctx);
2444 return -1;
2447 status = ads_startup(c, true, tmp_ctx, &ads);
2448 if (!ADS_ERR_OK(status)) {
2449 goto out;
2452 if (argc > 1) {
2453 servername = argv[1];
2454 } else {
2455 servername = lp_netbios_name();
2458 status = ads_find_printer_on_server(ads, &res, argv[0], servername);
2459 if (!ADS_ERR_OK(status)) {
2460 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"),
2461 ads_errstr(status));
2462 goto out;
2465 if (ads_count_replies(ads, res) == 0) {
2466 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2467 goto out;
2470 prt_dn = ads_get_dn(ads, tmp_ctx, res);
2471 if (prt_dn == NULL) {
2472 d_fprintf(stderr, _("Out of memory\n"));
2473 goto out;
2476 status = ads_del_dn(ads, prt_dn);
2477 if (!ADS_ERR_OK(status)) {
2478 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(status));
2479 goto out;
2482 ret = 0;
2483 out:
2484 ads_msgfree(ads, res);
2485 TALLOC_FREE(tmp_ctx);
2486 return ret;
2489 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2491 struct functable func[] = {
2493 "search",
2494 net_ads_printer_search,
2495 NET_TRANSPORT_ADS,
2496 N_("Search for a printer"),
2497 N_("net ads printer search\n"
2498 " Search for a printer")
2501 "info",
2502 net_ads_printer_info,
2503 NET_TRANSPORT_ADS,
2504 N_("Display printer information"),
2505 N_("net ads printer info\n"
2506 " Display printer information")
2509 "publish",
2510 net_ads_printer_publish,
2511 NET_TRANSPORT_ADS,
2512 N_("Publish a printer"),
2513 N_("net ads printer publish\n"
2514 " Publish a printer")
2517 "remove",
2518 net_ads_printer_remove,
2519 NET_TRANSPORT_ADS,
2520 N_("Delete a printer"),
2521 N_("net ads printer remove\n"
2522 " Delete a printer")
2524 {NULL, NULL, 0, NULL, NULL}
2527 return net_run_function(c, argc, argv, "net ads printer", func);
2531 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2533 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2534 ADS_STRUCT *ads = NULL;
2535 const char *auth_principal = cli_credentials_get_username(c->creds);
2536 const char *auth_password = cli_credentials_get_password(c->creds);
2537 const char *realm = NULL;
2538 char *new_password = NULL;
2539 char *chr = NULL;
2540 char *prompt = NULL;
2541 const char *user = NULL;
2542 char pwd[256] = {0};
2543 ADS_STATUS status;
2544 int ret = 0;
2546 if (c->display_usage) {
2547 d_printf("%s\n%s",
2548 _("Usage:"),
2549 _("net ads password <username>\n"
2550 " Change password for user\n"
2551 " username\tName of user to change password for\n"));
2552 TALLOC_FREE(tmp_ctx);
2553 return -1;
2556 if (auth_principal == NULL || auth_password == NULL) {
2557 d_fprintf(stderr, _("You must supply an administrator "
2558 "username/password\n"));
2559 TALLOC_FREE(tmp_ctx);
2560 return -1;
2563 if (argc < 1) {
2564 d_fprintf(stderr, _("ERROR: You must say which username to "
2565 "change password for\n"));
2566 TALLOC_FREE(tmp_ctx);
2567 return -1;
2570 if (strchr_m(argv[0], '@')) {
2571 user = talloc_strdup(tmp_ctx, argv[0]);
2572 } else {
2573 user = talloc_asprintf(tmp_ctx, "%s@%s", argv[0], lp_realm());
2575 if (user == NULL) {
2576 d_fprintf(stderr, _("Out of memory\n"));
2577 goto out;
2580 chr = strchr_m(auth_principal, '@');
2581 if (chr) {
2582 realm = ++chr;
2583 } else {
2584 realm = lp_realm();
2587 /* use the realm so we can eventually change passwords for users
2588 in realms other than default */
2589 ads = ads_init(tmp_ctx,
2590 realm,
2591 c->opt_workgroup,
2592 c->opt_host,
2593 ADS_SASL_PLAIN);
2594 if (ads == NULL) {
2595 goto out;
2598 /* we don't actually need a full connect, but it's the easy way to
2599 fill in the KDC's address */
2600 ads->auth.flags |= ADS_AUTH_GENERATE_KRB5_CONFIG;
2601 ads_connect_cldap_only(ads);
2603 if (!ads->config.realm) {
2604 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2605 goto out;
2608 if (argv[1] != NULL) {
2609 new_password = talloc_strdup(tmp_ctx, argv[1]);
2610 } else {
2611 int rc;
2613 prompt = talloc_asprintf(tmp_ctx, _("Enter new password for %s:"), user);
2614 if (prompt == NULL) {
2615 d_fprintf(stderr, _("Out of memory\n"));
2616 goto out;
2619 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2620 if (rc < 0) {
2621 goto out;
2623 new_password = talloc_strdup(tmp_ctx, pwd);
2624 memset(pwd, '\0', sizeof(pwd));
2627 if (new_password == NULL) {
2628 d_fprintf(stderr, _("Out of memory\n"));
2629 goto out;
2632 status = kerberos_set_password(auth_principal,
2633 auth_password,
2634 user,
2635 new_password);
2636 memset(new_password, '\0', strlen(new_password));
2637 if (!ADS_ERR_OK(status)) {
2638 d_fprintf(stderr, _("Password change failed: %s\n"),
2639 ads_errstr(status));
2640 goto out;
2643 d_printf(_("Password change for %s completed.\n"), user);
2645 ret = 0;
2646 out:
2647 TALLOC_FREE(tmp_ctx);
2648 return ret;
2651 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2653 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2654 ADS_STRUCT *ads = NULL;
2655 char *host_principal = NULL;
2656 char *my_name = NULL;
2657 ADS_STATUS status;
2658 int ret = -1;
2660 if (c->display_usage) {
2661 d_printf( "%s\n"
2662 "net ads changetrustpw\n"
2663 " %s\n",
2664 _("Usage:"),
2665 _("Change the machine account's trust password"));
2666 TALLOC_FREE(tmp_ctx);
2667 return -1;
2670 if (!secrets_init()) {
2671 DEBUG(1,("Failed to initialise secrets database\n"));
2672 goto out;
2675 net_warn_member_options();
2677 net_use_krb_machine_account(c);
2679 status = ads_startup(c, true, tmp_ctx, &ads);
2680 if (!ADS_ERR_OK(status)) {
2681 goto out;
2684 my_name = talloc_asprintf_strlower_m(tmp_ctx, "%s", lp_netbios_name());
2685 if (my_name == NULL) {
2686 d_fprintf(stderr, _("Out of memory\n"));
2687 goto out;
2690 host_principal = talloc_asprintf(tmp_ctx, "%s$@%s", my_name, ads->config.realm);
2691 if (host_principal == NULL) {
2692 d_fprintf(stderr, _("Out of memory\n"));
2693 goto out;
2696 d_printf(_("Changing password for principal: %s\n"), host_principal);
2698 status = ads_change_trust_account_password(ads, host_principal);
2699 if (!ADS_ERR_OK(status)) {
2700 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(status));
2701 goto out;
2704 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2706 ret = 0;
2707 out:
2708 TALLOC_FREE(tmp_ctx);
2710 return ret;
2714 help for net ads search
2716 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2718 d_printf(_(
2719 "\nnet ads search <expression> <attributes...>\n"
2720 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2721 "The expression is a standard LDAP search expression, and the\n"
2722 "attributes are a list of LDAP fields to show in the results.\n\n"
2723 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2725 net_common_flags_usage(c, argc, argv);
2726 return -1;
2731 general ADS search function. Useful in diagnosing problems in ADS
2733 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2735 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2736 ADS_STRUCT *ads = NULL;
2737 ADS_STATUS status;
2738 const char *ldap_exp = NULL;
2739 const char **attrs = NULL;
2740 LDAPMessage *res = NULL;
2741 int ret = -1;
2743 if (argc < 1 || c->display_usage) {
2744 TALLOC_FREE(tmp_ctx);
2745 return net_ads_search_usage(c, argc, argv);
2748 status = ads_startup(c, false, tmp_ctx, &ads);
2749 if (!ADS_ERR_OK(status)) {
2750 goto out;
2753 ldap_exp = argv[0];
2754 attrs = (argv + 1);
2756 status = ads_do_search_retry(ads,
2757 ads->config.bind_path,
2758 LDAP_SCOPE_SUBTREE,
2759 ldap_exp,
2760 attrs,
2761 &res);
2762 if (!ADS_ERR_OK(status)) {
2763 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(status));
2764 goto out;
2767 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2769 /* dump the results */
2770 ads_dump(ads, res);
2772 ret = 0;
2773 out:
2774 ads_msgfree(ads, res);
2775 TALLOC_FREE(tmp_ctx);
2776 return ret;
2781 help for net ads search
2783 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2785 d_printf(_(
2786 "\nnet ads dn <dn> <attributes...>\n"
2787 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2788 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2789 "to show in the results\n\n"
2790 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2791 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2793 net_common_flags_usage(c, argc, argv);
2794 return -1;
2799 general ADS search function. Useful in diagnosing problems in ADS
2801 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2803 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2804 ADS_STRUCT *ads = NULL;
2805 ADS_STATUS status;
2806 const char *dn = NULL;
2807 const char **attrs = NULL;
2808 LDAPMessage *res = NULL;
2809 int ret = -1;
2811 if (argc < 1 || c->display_usage) {
2812 TALLOC_FREE(tmp_ctx);
2813 return net_ads_dn_usage(c, argc, argv);
2816 status = ads_startup(c, false, tmp_ctx, &ads);
2817 if (!ADS_ERR_OK(status)) {
2818 goto out;
2821 dn = argv[0];
2822 attrs = (argv + 1);
2824 status = ads_do_search_all(ads,
2826 LDAP_SCOPE_BASE,
2827 "(objectclass=*)",
2828 attrs,
2829 &res);
2830 if (!ADS_ERR_OK(status)) {
2831 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(status));
2832 goto out;
2835 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2837 /* dump the results */
2838 ads_dump(ads, res);
2840 ret = 0;
2841 out:
2842 ads_msgfree(ads, res);
2843 TALLOC_FREE(tmp_ctx);
2844 return ret;
2848 help for net ads sid search
2850 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2852 d_printf(_(
2853 "\nnet ads sid <sid> <attributes...>\n"
2854 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2855 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2856 "to show in the results\n\n"
2857 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2859 net_common_flags_usage(c, argc, argv);
2860 return -1;
2865 general ADS search function. Useful in diagnosing problems in ADS
2867 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2869 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2870 ADS_STRUCT *ads = NULL;
2871 ADS_STATUS status;
2872 const char *sid_string = NULL;
2873 const char **attrs = NULL;
2874 LDAPMessage *res = NULL;
2875 struct dom_sid sid = { 0 };
2876 int ret = -1;
2878 if (argc < 1 || c->display_usage) {
2879 TALLOC_FREE(tmp_ctx);
2880 return net_ads_sid_usage(c, argc, argv);
2883 status = ads_startup(c, false, tmp_ctx, &ads);
2884 if (!ADS_ERR_OK(status)) {
2885 goto out;
2888 sid_string = argv[0];
2889 attrs = (argv + 1);
2891 if (!string_to_sid(&sid, sid_string)) {
2892 d_fprintf(stderr, _("could not convert sid\n"));
2893 goto out;
2896 status = ads_search_retry_sid(ads, &res, &sid, attrs);
2897 if (!ADS_ERR_OK(status)) {
2898 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(status));
2899 goto out;
2902 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2904 /* dump the results */
2905 ads_dump(ads, res);
2907 ret = 0;
2908 out:
2909 ads_msgfree(ads, res);
2910 TALLOC_FREE(tmp_ctx);
2911 return ret;
2914 static int net_ads_keytab_flush(struct net_context *c,
2915 int argc,
2916 const char **argv)
2918 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2919 ADS_STRUCT *ads = NULL;
2920 ADS_STATUS status;
2921 int ret = -1;
2923 if (c->display_usage) {
2924 d_printf( "%s\n"
2925 "net ads keytab flush\n"
2926 " %s\n",
2927 _("Usage:"),
2928 _("Delete the whole keytab"));
2929 TALLOC_FREE(tmp_ctx);
2930 return -1;
2933 if (!c->explicit_credentials) {
2934 net_use_krb_machine_account(c);
2937 status = ads_startup(c, true, tmp_ctx, &ads);
2938 if (!ADS_ERR_OK(status)) {
2939 goto out;
2942 ret = ads_keytab_flush(ads);
2943 out:
2944 TALLOC_FREE(tmp_ctx);
2945 return ret;
2948 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2950 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2951 ADS_STRUCT *ads = NULL;
2952 ADS_STATUS status;
2953 NTSTATUS ntstatus;
2954 int ret = -1;
2956 if (c->display_usage) {
2957 d_printf( "%s\n"
2958 "net ads keytab create\n"
2959 " %s\n",
2960 _("Usage:"),
2961 _("Create (sync) new default keytab"));
2962 TALLOC_FREE(tmp_ctx);
2963 return -1;
2966 net_warn_member_options();
2968 if (!c->explicit_credentials) {
2969 net_use_krb_machine_account(c);
2972 status = ads_startup(c, true, tmp_ctx, &ads);
2973 if (!ADS_ERR_OK(status)) {
2974 goto out;
2977 ntstatus = sync_pw2keytabs();
2978 ret = NT_STATUS_IS_OK(ntstatus) ? 0 : 1;
2979 out:
2980 TALLOC_FREE(tmp_ctx);
2981 return ret;
2984 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2986 const char *keytab = NULL;
2988 if (c->display_usage) {
2989 d_printf("%s\n%s",
2990 _("Usage:"),
2991 _("net ads keytab list [keytab]\n"
2992 " List a local keytab\n"
2993 " keytab\tKeytab to list\n"));
2994 return -1;
2997 if (argc >= 1) {
2998 keytab = argv[0];
3001 return ads_keytab_list(keytab);
3004 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3006 struct functable func[] = {
3008 "create",
3009 net_ads_keytab_create,
3010 NET_TRANSPORT_ADS,
3011 N_("Create (sync) a fresh keytab"),
3012 N_("net ads keytab create\n"
3013 " Create (sync) a fresh keytab or update existing one (see also smb.conf 'sync machine password to keytab'.")
3016 "flush",
3017 net_ads_keytab_flush,
3018 NET_TRANSPORT_ADS,
3019 N_("Remove all keytab entries"),
3020 N_("net ads keytab flush\n"
3021 " Remove all keytab entries")
3024 "list",
3025 net_ads_keytab_list,
3026 NET_TRANSPORT_ADS,
3027 N_("List a keytab"),
3028 N_("net ads keytab list\n"
3029 " List a keytab")
3031 {NULL, NULL, 0, NULL, NULL}
3034 return net_run_function(c, argc, argv, "net ads keytab", func);
3037 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
3039 int ret = -1;
3041 if (c->display_usage) {
3042 d_printf( "%s\n"
3043 "net ads kerberos renew\n"
3044 " %s\n",
3045 _("Usage:"),
3046 _("Renew TGT from existing credential cache"));
3047 return -1;
3050 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
3051 if (ret) {
3052 d_printf(_("failed to renew kerberos ticket: %s\n"),
3053 error_message(ret));
3055 return ret;
3058 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
3059 struct PAC_DATA_CTR **pac_data_ctr)
3061 NTSTATUS status;
3062 int ret = -1;
3063 const char *impersonate_princ_s = NULL;
3064 const char *local_service = NULL;
3065 const char *principal = NULL;
3066 const char *password = NULL;
3067 int i;
3069 for (i=0; i<argc; i++) {
3070 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
3071 impersonate_princ_s = get_string_param(argv[i]);
3072 if (impersonate_princ_s == NULL) {
3073 return -1;
3076 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
3077 local_service = get_string_param(argv[i]);
3078 if (local_service == NULL) {
3079 return -1;
3084 if (local_service == NULL) {
3085 local_service = talloc_asprintf(c, "%s$@%s",
3086 lp_netbios_name(), lp_realm());
3087 if (local_service == NULL) {
3088 goto out;
3092 principal = cli_credentials_get_principal(c->creds, c);
3093 if (principal == NULL) {
3094 d_printf("cli_credentials_get_principal() failed\n");
3095 goto out;
3097 password = cli_credentials_get_password(c->creds);
3099 status = kerberos_return_pac(c,
3100 principal,
3101 password,
3103 NULL,
3104 NULL,
3105 NULL,
3106 true,
3107 true,
3108 2592000, /* one month */
3109 impersonate_princ_s,
3110 local_service,
3111 NULL,
3112 NULL,
3113 pac_data_ctr);
3114 if (!NT_STATUS_IS_OK(status)) {
3115 d_printf(_("failed to query kerberos PAC: %s\n"),
3116 nt_errstr(status));
3117 goto out;
3120 ret = 0;
3121 out:
3122 return ret;
3125 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
3127 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3128 int i, num_buffers;
3129 int ret = -1;
3130 enum PAC_TYPE type = 0;
3132 if (c->display_usage) {
3133 d_printf( "%s\n"
3134 "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
3135 " %s\n",
3136 _("Usage:"),
3137 _("Dump the Kerberos PAC"));
3138 return -1;
3141 for (i=0; i<argc; i++) {
3142 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
3143 type = get_int_param(argv[i]);
3147 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3148 if (ret) {
3149 return ret;
3152 if (type == 0) {
3154 char *s = NULL;
3156 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
3157 pac_data_ctr->pac_data);
3158 if (s != NULL) {
3159 d_printf(_("The Pac: %s\n"), s);
3160 talloc_free(s);
3163 return 0;
3166 num_buffers = pac_data_ctr->pac_data->num_buffers;
3168 for (i=0; i<num_buffers; i++) {
3170 char *s = NULL;
3172 if (pac_data_ctr->pac_data->buffers[i].type != type) {
3173 continue;
3176 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
3177 pac_data_ctr->pac_data->buffers[i].info);
3178 if (s != NULL) {
3179 d_printf(_("The Pac: %s\n"), s);
3180 talloc_free(s);
3182 break;
3185 return 0;
3188 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
3190 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3191 char *filename = NULL;
3192 int ret = -1;
3193 int i;
3195 if (c->display_usage) {
3196 d_printf( "%s\n"
3197 "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3198 " %s\n",
3199 _("Usage:"),
3200 _("Save the Kerberos PAC"));
3201 return -1;
3204 for (i=0; i<argc; i++) {
3205 if (strnequal(argv[i], "filename", strlen("filename"))) {
3206 filename = get_string_param(argv[i]);
3207 if (filename == NULL) {
3208 return -1;
3213 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3214 if (ret) {
3215 return ret;
3218 if (filename == NULL) {
3219 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3220 return -1;
3223 /* save the raw format */
3224 if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
3225 d_printf(_("failed to save PAC in %s\n"), filename);
3226 return -1;
3229 return 0;
3232 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
3234 struct functable func[] = {
3236 "dump",
3237 net_ads_kerberos_pac_dump,
3238 NET_TRANSPORT_ADS,
3239 N_("Dump Kerberos PAC"),
3240 N_("net ads kerberos pac dump\n"
3241 " Dump a Kerberos PAC to stdout")
3244 "save",
3245 net_ads_kerberos_pac_save,
3246 NET_TRANSPORT_ADS,
3247 N_("Save Kerberos PAC"),
3248 N_("net ads kerberos pac save\n"
3249 " Save a Kerberos PAC in a file")
3252 {NULL, NULL, 0, NULL, NULL}
3255 return net_run_function(c, argc, argv, "net ads kerberos pac", func);
3258 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
3260 int ret = -1;
3261 NTSTATUS status;
3262 const char *principal = NULL;
3263 const char *password = NULL;
3265 if (c->display_usage) {
3266 d_printf( "%s\n"
3267 "net ads kerberos kinit\n"
3268 " %s\n",
3269 _("Usage:"),
3270 _("Get Ticket Granting Ticket (TGT) for the user"));
3271 return -1;
3274 principal = cli_credentials_get_principal(c->creds, c);
3275 if (principal == NULL) {
3276 d_printf("cli_credentials_get_principal() failed\n");
3277 return -1;
3279 password = cli_credentials_get_password(c->creds);
3281 ret = kerberos_kinit_password_ext(principal,
3282 password,
3284 NULL,
3285 NULL,
3286 NULL,
3287 true,
3288 true,
3289 2592000, /* one month */
3290 NULL,
3291 NULL,
3292 NULL,
3293 &status);
3294 if (ret) {
3295 d_printf(_("failed to kinit password: %s\n"),
3296 nt_errstr(status));
3298 return ret;
3301 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3303 struct functable func[] = {
3305 "kinit",
3306 net_ads_kerberos_kinit,
3307 NET_TRANSPORT_ADS,
3308 N_("Retrieve Ticket Granting Ticket (TGT)"),
3309 N_("net ads kerberos kinit\n"
3310 " Receive Ticket Granting Ticket (TGT)")
3313 "renew",
3314 net_ads_kerberos_renew,
3315 NET_TRANSPORT_ADS,
3316 N_("Renew Ticket Granting Ticket from credential cache"),
3317 N_("net ads kerberos renew\n"
3318 " Renew Ticket Granting Ticket (TGT) from "
3319 "credential cache")
3322 "pac",
3323 net_ads_kerberos_pac,
3324 NET_TRANSPORT_ADS,
3325 N_("Dump Kerberos PAC"),
3326 N_("net ads kerberos pac\n"
3327 " Dump Kerberos PAC")
3329 {NULL, NULL, 0, NULL, NULL}
3332 return net_run_function(c, argc, argv, "net ads kerberos", func);
3335 static int net_ads_setspn_list(struct net_context *c,
3336 int argc,
3337 const char **argv)
3339 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3340 ADS_STRUCT *ads = NULL;
3341 ADS_STATUS status;
3342 bool ok = false;
3343 int ret = -1;
3345 if (c->display_usage) {
3346 d_printf("%s\n%s",
3347 _("Usage:"),
3348 _("net ads setspn list [machinename]\n"));
3349 TALLOC_FREE(tmp_ctx);
3350 return -1;
3353 status = ads_startup(c, true, tmp_ctx, &ads);
3354 if (!ADS_ERR_OK(status)) {
3355 goto out;
3358 if (argc) {
3359 ok = ads_setspn_list(ads, argv[0]);
3360 } else {
3361 ok = ads_setspn_list(ads, lp_netbios_name());
3364 ret = ok ? 0 : -1;
3365 out:
3366 TALLOC_FREE(tmp_ctx);
3367 return ret;
3370 static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3372 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3373 ADS_STRUCT *ads = NULL;
3374 ADS_STATUS status;
3375 bool ok = false;
3376 int ret = -1;
3378 if (c->display_usage || argc < 1) {
3379 d_printf("%s\n%s",
3380 _("Usage:"),
3381 _("net ads setspn add [machinename] spn\n"));
3382 TALLOC_FREE(tmp_ctx);
3383 return -1;
3386 status = ads_startup(c, true, tmp_ctx, &ads);
3387 if (!ADS_ERR_OK(status)) {
3388 goto out;
3391 if (argc > 1) {
3392 ok = ads_setspn_add(ads, argv[0], argv[1]);
3393 } else {
3394 ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3397 ret = ok ? 0 : -1;
3398 out:
3399 TALLOC_FREE(tmp_ctx);
3400 return ret;
3403 static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3405 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3406 ADS_STRUCT *ads = NULL;
3407 ADS_STATUS status;
3408 bool ok = false;
3409 int ret = -1;
3411 if (c->display_usage || argc < 1) {
3412 d_printf("%s\n%s",
3413 _("Usage:"),
3414 _("net ads setspn delete [machinename] spn\n"));
3415 TALLOC_FREE(tmp_ctx);
3416 return -1;
3419 status = ads_startup(c, true, tmp_ctx, &ads);
3420 if (!ADS_ERR_OK(status)) {
3421 goto out;
3424 if (argc > 1) {
3425 ok = ads_setspn_delete(ads, argv[0], argv[1]);
3426 } else {
3427 ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3430 ret = ok ? 0 : -1;
3431 out:
3432 TALLOC_FREE(tmp_ctx);
3433 return ret;
3436 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3438 struct functable func[] = {
3440 "list",
3441 net_ads_setspn_list,
3442 NET_TRANSPORT_ADS,
3443 N_("List Service Principal Names (SPN)"),
3444 N_("net ads setspn list [machine]\n"
3445 " List Service Principal Names (SPN)")
3448 "add",
3449 net_ads_setspn_add,
3450 NET_TRANSPORT_ADS,
3451 N_("Add Service Principal Names (SPN)"),
3452 N_("net ads setspn add [machine] spn\n"
3453 " Add Service Principal Names (SPN)")
3456 "delete",
3457 net_ads_setspn_delete,
3458 NET_TRANSPORT_ADS,
3459 N_("Delete Service Principal Names (SPN)"),
3460 N_("net ads setspn delete [machine] spn\n"
3461 " Delete Service Principal Names (SPN)")
3463 {NULL, NULL, 0, NULL, NULL}
3466 return net_run_function(c, argc, argv, "net ads setspn", func);
3469 static int net_ads_enctype_lookup_account(struct net_context *c,
3470 ADS_STRUCT *ads,
3471 const char *account,
3472 LDAPMessage **res,
3473 const char **enctype_str)
3475 const char *filter;
3476 const char *attrs[] = {
3477 "msDS-SupportedEncryptionTypes",
3478 NULL
3480 int count;
3481 int ret = -1;
3482 ADS_STATUS status;
3484 filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3485 account);
3486 if (filter == NULL) {
3487 goto done;
3490 status = ads_search(ads, res, filter, attrs);
3491 if (!ADS_ERR_OK(status)) {
3492 d_printf(_("no account found with filter: %s\n"), filter);
3493 goto done;
3496 count = ads_count_replies(ads, *res);
3497 switch (count) {
3498 case 1:
3499 break;
3500 case 0:
3501 d_printf(_("no account found with filter: %s\n"), filter);
3502 goto done;
3503 default:
3504 d_printf(_("multiple accounts found with filter: %s\n"), filter);
3505 goto done;
3508 if (enctype_str) {
3509 *enctype_str = ads_pull_string(ads, c, *res,
3510 "msDS-SupportedEncryptionTypes");
3511 if (*enctype_str == NULL) {
3512 d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3513 goto done;
3517 ret = 0;
3518 done:
3519 return ret;
3522 static void net_ads_enctype_dump_enctypes(const char *username,
3523 const char *enctype_str)
3525 int enctypes = atoi(enctype_str);
3527 d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3528 username, enctypes, enctypes);
3530 printf("[%s] 0x%08x DES-CBC-CRC\n",
3531 enctypes & ENC_CRC32 ? "X" : " ",
3532 ENC_CRC32);
3533 printf("[%s] 0x%08x DES-CBC-MD5\n",
3534 enctypes & ENC_RSA_MD5 ? "X" : " ",
3535 ENC_RSA_MD5);
3536 printf("[%s] 0x%08x RC4-HMAC\n",
3537 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3538 ENC_RC4_HMAC_MD5);
3539 printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3540 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3541 ENC_HMAC_SHA1_96_AES128);
3542 printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3543 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3544 ENC_HMAC_SHA1_96_AES256);
3545 printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96-SK\n",
3546 enctypes & ENC_HMAC_SHA1_96_AES256_SK ? "X" : " ",
3547 ENC_HMAC_SHA1_96_AES256_SK);
3548 printf("[%s] 0x%08x RESOURCE-SID-COMPRESSION-DISABLED\n",
3549 enctypes & KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED ? "X" : " ",
3550 KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED);
3553 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3555 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3556 ADS_STATUS status;
3557 ADS_STRUCT *ads = NULL;
3558 LDAPMessage *res = NULL;
3559 const char *str = NULL;
3560 int ret = -1;
3562 if (c->display_usage || (argc < 1)) {
3563 d_printf( "%s\n"
3564 "net ads enctypes list <account_name>\n"
3565 " %s\n",
3566 _("Usage:"),
3567 _("List supported enctypes"));
3568 TALLOC_FREE(tmp_ctx);
3569 return -1;
3572 status = ads_startup(c, false, tmp_ctx, &ads);
3573 if (!ADS_ERR_OK(status)) {
3574 goto out;
3577 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3578 if (ret) {
3579 goto out;
3582 net_ads_enctype_dump_enctypes(argv[0], str);
3584 ret = 0;
3585 out:
3586 ads_msgfree(ads, res);
3587 TALLOC_FREE(tmp_ctx);
3588 return ret;
3591 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3593 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3594 int ret = -1;
3595 ADS_STATUS status;
3596 ADS_STRUCT *ads = NULL;
3597 LDAPMessage *res = NULL;
3598 const char *etype_list_str = NULL;
3599 const char *dn = NULL;
3600 ADS_MODLIST mods = NULL;
3601 uint32_t etype_list;
3602 const char *str = NULL;
3604 if (c->display_usage || argc < 1) {
3605 d_printf( "%s\n"
3606 "net ads enctypes set <sAMAccountName> [enctypes]\n"
3607 " %s\n",
3608 _("Usage:"),
3609 _("Set supported enctypes"));
3610 TALLOC_FREE(tmp_ctx);
3611 return -1;
3614 status = ads_startup(c, false, tmp_ctx, &ads);
3615 if (!ADS_ERR_OK(status)) {
3616 goto done;
3619 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3620 if (ret) {
3621 goto done;
3624 dn = ads_get_dn(ads, tmp_ctx, res);
3625 if (dn == NULL) {
3626 goto done;
3629 etype_list = 0;
3630 etype_list |= ENC_RC4_HMAC_MD5;
3631 etype_list |= ENC_HMAC_SHA1_96_AES128;
3632 etype_list |= ENC_HMAC_SHA1_96_AES256;
3634 if (argv[1] != NULL) {
3635 sscanf(argv[1], "%i", &etype_list);
3638 etype_list_str = talloc_asprintf(tmp_ctx, "%d", etype_list);
3639 if (!etype_list_str) {
3640 goto done;
3643 mods = ads_init_mods(tmp_ctx);
3644 if (!mods) {
3645 goto done;
3648 status = ads_mod_str(tmp_ctx, &mods, "msDS-SupportedEncryptionTypes",
3649 etype_list_str);
3650 if (!ADS_ERR_OK(status)) {
3651 goto done;
3654 status = ads_gen_mod(ads, dn, mods);
3655 if (!ADS_ERR_OK(status)) {
3656 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3657 ads_errstr(status));
3658 goto done;
3661 ads_msgfree(ads, res);
3662 res = NULL;
3664 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3665 if (ret) {
3666 goto done;
3669 net_ads_enctype_dump_enctypes(argv[0], str);
3671 ret = 0;
3672 done:
3673 ads_msgfree(ads, res);
3674 TALLOC_FREE(tmp_ctx);
3675 return ret;
3678 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3680 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3681 int ret = -1;
3682 ADS_STATUS status;
3683 ADS_STRUCT *ads = NULL;
3684 LDAPMessage *res = NULL;
3685 const char *dn = NULL;
3686 ADS_MODLIST mods = NULL;
3688 if (c->display_usage || argc < 1) {
3689 d_printf( "%s\n"
3690 "net ads enctypes delete <sAMAccountName>\n"
3691 " %s\n",
3692 _("Usage:"),
3693 _("Delete supported enctypes"));
3694 TALLOC_FREE(tmp_ctx);
3695 return -1;
3698 status = ads_startup(c, false, tmp_ctx, &ads);
3699 if (!ADS_ERR_OK(status)) {
3700 goto done;
3703 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3704 if (ret) {
3705 goto done;
3708 dn = ads_get_dn(ads, tmp_ctx, res);
3709 if (dn == NULL) {
3710 goto done;
3713 mods = ads_init_mods(tmp_ctx);
3714 if (!mods) {
3715 goto done;
3718 status = ads_mod_str(tmp_ctx, &mods, "msDS-SupportedEncryptionTypes", NULL);
3719 if (!ADS_ERR_OK(status)) {
3720 goto done;
3723 status = ads_gen_mod(ads, dn, mods);
3724 if (!ADS_ERR_OK(status)) {
3725 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3726 ads_errstr(status));
3727 goto done;
3730 ret = 0;
3732 done:
3733 ads_msgfree(ads, res);
3734 TALLOC_FREE(tmp_ctx);
3735 return ret;
3738 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3740 struct functable func[] = {
3742 "list",
3743 net_ads_enctypes_list,
3744 NET_TRANSPORT_ADS,
3745 N_("List the supported encryption types"),
3746 N_("net ads enctypes list <account_name>\n"
3747 " List the supported encryption types")
3750 "set",
3751 net_ads_enctypes_set,
3752 NET_TRANSPORT_ADS,
3753 N_("Set the supported encryption types"),
3754 N_("net ads enctypes set <account_name> [enctypes]\n"
3755 " Set the supported encryption types")
3758 "delete",
3759 net_ads_enctypes_delete,
3760 NET_TRANSPORT_ADS,
3761 N_("Delete the msDS-SupportedEncryptionTypes attribute"),
3762 N_("net ads enctypes delete <account_name>\n"
3763 " Delete the LDAP attribute")
3766 {NULL, NULL, 0, NULL, NULL}
3769 return net_run_function(c, argc, argv, "net ads enctypes", func);
3773 int net_ads(struct net_context *c, int argc, const char **argv)
3775 struct functable func[] = {
3777 "info",
3778 net_ads_info,
3779 NET_TRANSPORT_ADS,
3780 N_("Display details on remote ADS server"),
3781 N_("net ads info\n"
3782 " Display details on remote ADS server")
3785 "join",
3786 net_ads_join,
3787 NET_TRANSPORT_ADS,
3788 N_("Join the local machine to ADS realm"),
3789 N_("net ads join\n"
3790 " Join the local machine to ADS realm")
3793 "testjoin",
3794 net_ads_testjoin,
3795 NET_TRANSPORT_ADS,
3796 N_("Validate machine account"),
3797 N_("net ads testjoin\n"
3798 " Validate machine account")
3801 "leave",
3802 net_ads_leave,
3803 NET_TRANSPORT_ADS,
3804 N_("Remove the local machine from ADS"),
3805 N_("net ads leave\n"
3806 " Remove the local machine from ADS")
3809 "status",
3810 net_ads_status,
3811 NET_TRANSPORT_ADS,
3812 N_("Display machine account details"),
3813 N_("net ads status\n"
3814 " Display machine account details")
3817 "user",
3818 net_ads_user,
3819 NET_TRANSPORT_ADS,
3820 N_("List/modify users"),
3821 N_("net ads user\n"
3822 " List/modify users")
3825 "group",
3826 net_ads_group,
3827 NET_TRANSPORT_ADS,
3828 N_("List/modify groups"),
3829 N_("net ads group\n"
3830 " List/modify groups")
3833 "dns",
3834 net_ads_dns,
3835 NET_TRANSPORT_ADS,
3836 N_("Issue dynamic DNS update"),
3837 N_("net ads dns\n"
3838 " Issue dynamic DNS update")
3841 "password",
3842 net_ads_password,
3843 NET_TRANSPORT_ADS,
3844 N_("Change user passwords"),
3845 N_("net ads password\n"
3846 " Change user passwords")
3849 "changetrustpw",
3850 net_ads_changetrustpw,
3851 NET_TRANSPORT_ADS,
3852 N_("Change trust account password"),
3853 N_("net ads changetrustpw\n"
3854 " Change trust account password")
3857 "printer",
3858 net_ads_printer,
3859 NET_TRANSPORT_ADS,
3860 N_("List/modify printer entries"),
3861 N_("net ads printer\n"
3862 " List/modify printer entries")
3865 "search",
3866 net_ads_search,
3867 NET_TRANSPORT_ADS,
3868 N_("Issue LDAP search using filter"),
3869 N_("net ads search\n"
3870 " Issue LDAP search using filter")
3873 "dn",
3874 net_ads_dn,
3875 NET_TRANSPORT_ADS,
3876 N_("Issue LDAP search by DN"),
3877 N_("net ads dn\n"
3878 " Issue LDAP search by DN")
3881 "sid",
3882 net_ads_sid,
3883 NET_TRANSPORT_ADS,
3884 N_("Issue LDAP search by SID"),
3885 N_("net ads sid\n"
3886 " Issue LDAP search by SID")
3889 "workgroup",
3890 net_ads_workgroup,
3891 NET_TRANSPORT_ADS,
3892 N_("Display workgroup name"),
3893 N_("net ads workgroup\n"
3894 " Display the workgroup name")
3897 "lookup",
3898 net_ads_lookup,
3899 NET_TRANSPORT_ADS,
3900 N_("Perform CLDAP query on DC"),
3901 N_("net ads lookup\n"
3902 " Find the ADS DC using CLDAP lookups")
3905 "keytab",
3906 net_ads_keytab,
3907 NET_TRANSPORT_ADS,
3908 N_("Manage local keytab file"),
3909 N_("net ads keytab\n"
3910 " Manage local keytab file")
3913 "setspn",
3914 net_ads_setspn,
3915 NET_TRANSPORT_ADS,
3916 N_("Manage Service Principal Names (SPN)s"),
3917 N_("net ads spnset\n"
3918 " Manage Service Principal Names (SPN)s")
3921 "gpo",
3922 net_ads_gpo,
3923 NET_TRANSPORT_ADS,
3924 N_("Manage group policy objects"),
3925 N_("net ads gpo\n"
3926 " Manage group policy objects")
3929 "kerberos",
3930 net_ads_kerberos,
3931 NET_TRANSPORT_ADS,
3932 N_("Manage kerberos keytab"),
3933 N_("net ads kerberos\n"
3934 " Manage kerberos keytab")
3937 "enctypes",
3938 net_ads_enctypes,
3939 NET_TRANSPORT_ADS,
3940 N_("List/modify supported encryption types"),
3941 N_("net ads enctypes\n"
3942 " List/modify enctypes")
3944 {NULL, NULL, 0, NULL, NULL}
3947 return net_run_function(c, argc, argv, "net ads", func);
3950 #else
3952 static int net_ads_noads(void)
3954 d_fprintf(stderr, _("ADS support not compiled in\n"));
3955 return -1;
3958 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3960 return net_ads_noads();
3963 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3965 return net_ads_noads();
3968 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3970 return net_ads_noads();
3973 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
3975 return net_ads_noads();
3978 int net_ads_join(struct net_context *c, int argc, const char **argv)
3980 return net_ads_noads();
3983 int net_ads_user(struct net_context *c, int argc, const char **argv)
3985 return net_ads_noads();
3988 int net_ads_group(struct net_context *c, int argc, const char **argv)
3990 return net_ads_noads();
3993 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
3995 return net_ads_noads();
3998 /* this one shouldn't display a message */
3999 int net_ads_check(struct net_context *c)
4001 return -1;
4004 int net_ads_check_our_domain(struct net_context *c)
4006 return -1;
4009 int net_ads(struct net_context *c, int argc, const char **argv)
4011 return net_ads_noads();
4014 #endif /* HAVE_ADS */