2 Samba Unix/Linux SMB client library
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/>.
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"
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"
39 #include "../libcli/security/security.h"
40 #include "libsmb/libsmb.h"
41 #include "lib/param/loadparm.h"
42 #include "utils/net_dns.h"
46 #include "audit_logging.h" /* various JSON helpers */
47 #include "auth/common_auth.h"
48 #endif /* [HAVE_JANSSON] */
52 /* when we do not have sufficient input parameters to contact a remote domain
53 * we always fall back to our own realm - Guenther*/
55 static const char *assume_own_realm(struct net_context *c)
57 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
67 * note: JSON output deliberately bypasses gettext so as to provide the same
68 * output irrespective of the locale.
71 static int output_json(const struct json_object *jsobj)
73 TALLOC_CTX *ctx = NULL;
76 if (json_is_invalid(jsobj)) {
80 ctx = talloc_new(NULL);
82 d_fprintf(stderr, _("Out of memory\n"));
86 json = json_to_string(ctx, jsobj);
88 d_fprintf(stderr, _("error encoding to JSON\n"));
92 d_printf("%s\n", json);
98 static int net_ads_cldap_netlogon_json
101 const struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply)
103 struct json_object jsobj = json_new_object();
104 struct json_object flagsobj = json_new_object();
105 char response_type [32] = { '\0' };
108 if (json_is_invalid(&jsobj) || json_is_invalid(&flagsobj)) {
109 d_fprintf(stderr, _("error setting up JSON value\n"));
114 switch (reply->command) {
115 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
116 strncpy(response_type,
117 "LOGON_SAM_LOGON_USER_UNKNOWN_EX",
118 sizeof(response_type));
120 case LOGON_SAM_LOGON_RESPONSE_EX:
121 strncpy(response_type, "LOGON_SAM_LOGON_RESPONSE_EX",
122 sizeof(response_type));
125 snprintf(response_type, sizeof(response_type), "0x%x",
130 ret = json_add_string(&jsobj, "Information for Domain Controller",
136 ret = json_add_string(&jsobj, "Response Type", response_type);
141 ret = json_add_guid(&jsobj, "GUID", &reply->domain_uuid);
146 ret = json_add_bool(&flagsobj, "Is a PDC",
147 reply->server_type & NBT_SERVER_PDC);
152 ret = json_add_bool(&flagsobj, "Is a GC of the forest",
153 reply->server_type & NBT_SERVER_GC);
158 ret = json_add_bool(&flagsobj, "Is an LDAP server",
159 reply->server_type & NBT_SERVER_LDAP);
164 ret = json_add_bool(&flagsobj, "Supports DS",
165 reply->server_type & NBT_SERVER_DS);
170 ret = json_add_bool(&flagsobj, "Is running a KDC",
171 reply->server_type & NBT_SERVER_KDC);
176 ret = json_add_bool(&flagsobj, "Is running time services",
177 reply->server_type & NBT_SERVER_TIMESERV);
182 ret = json_add_bool(&flagsobj, "Is the closest DC",
183 reply->server_type & NBT_SERVER_CLOSEST);
188 ret = json_add_bool(&flagsobj, "Is writable",
189 reply->server_type & NBT_SERVER_WRITABLE);
194 ret = json_add_bool(&flagsobj, "Has a hardware clock",
195 reply->server_type & NBT_SERVER_GOOD_TIMESERV);
200 ret = json_add_bool(&flagsobj,
201 "Is a non-domain NC serviced by LDAP server",
202 reply->server_type & NBT_SERVER_NDNC);
208 (&flagsobj, "Is NT6 DC that has some secrets",
209 reply->server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6);
215 (&flagsobj, "Is NT6 DC that has all secrets",
216 reply->server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6);
221 ret = json_add_bool(&flagsobj, "Runs Active Directory Web Services",
222 reply->server_type & NBT_SERVER_ADS_WEB_SERVICE);
227 ret = json_add_bool(&flagsobj, "Runs on Windows 2012 or later",
228 reply->server_type & NBT_SERVER_DS_8);
233 ret = json_add_string(&jsobj, "Forest", reply->forest);
238 ret = json_add_string(&jsobj, "Domain", reply->dns_domain);
243 ret = json_add_string(&jsobj, "Domain Controller", reply->pdc_dns_name);
249 ret = json_add_string(&jsobj, "Pre-Win2k Domain", reply->domain_name);
254 ret = json_add_string(&jsobj, "Pre-Win2k Hostname", reply->pdc_name);
259 if (*reply->user_name) {
260 ret = json_add_string(&jsobj, "User name", reply->user_name);
266 ret = json_add_string(&jsobj, "Server Site Name", reply->server_site);
271 ret = json_add_string(&jsobj, "Client Site Name", reply->client_site);
276 ret = json_add_int(&jsobj, "NT Version", reply->nt_version);
281 ret = json_add_int(&jsobj, "LMNT Token", reply->lmnt_token);
286 ret = json_add_int(&jsobj, "LM20 Token", reply->lm20_token);
291 ret = json_add_object(&jsobj, "Flags", &flagsobj);
296 ret = output_json(&jsobj);
297 json_free(&jsobj); /* frees flagsobj recursively */
302 json_free(&flagsobj);
308 #else /* [HAVE_JANSSON] */
310 static int net_ads_cldap_netlogon_json
313 const struct NETLOGON_SAM_LOGON_RESPONSE_EX * reply)
315 d_fprintf(stderr, _("JSON support not available\n"));
320 #endif /* [HAVE_JANSSON] */
323 do a cldap netlogon query
325 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
327 char addr[INET6_ADDRSTRLEN];
328 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
330 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
332 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
333 d_fprintf(stderr, _("CLDAP query failed!\n"));
338 return net_ads_cldap_netlogon_json(ads, addr, &reply);
341 d_printf(_("Information for Domain Controller: %s\n\n"),
344 d_printf(_("Response Type: "));
345 switch (reply.command) {
346 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
347 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
349 case LOGON_SAM_LOGON_RESPONSE_EX:
350 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
353 d_printf("0x%x\n", reply.command);
357 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
359 d_printf(_("Flags:\n"
361 "\tIs a GC of the forest: %s\n"
362 "\tIs an LDAP server: %s\n"
363 "\tSupports DS: %s\n"
364 "\tIs running a KDC: %s\n"
365 "\tIs running time services: %s\n"
366 "\tIs the closest DC: %s\n"
367 "\tIs writable: %s\n"
368 "\tHas a hardware clock: %s\n"
369 "\tIs a non-domain NC serviced by LDAP server: %s\n"
370 "\tIs NT6 DC that has some secrets: %s\n"
371 "\tIs NT6 DC that has all secrets: %s\n"
372 "\tRuns Active Directory Web Services: %s\n"
373 "\tRuns on Windows 2012 or later: %s\n"),
374 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
375 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
376 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
377 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
378 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
379 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
380 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
381 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
382 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
383 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
384 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
385 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"),
386 (reply.server_type & NBT_SERVER_ADS_WEB_SERVICE) ? _("yes") : _("no"),
387 (reply.server_type & NBT_SERVER_DS_8) ? _("yes") : _("no"));
390 printf(_("Forest: %s\n"), reply.forest);
391 printf(_("Domain: %s\n"), reply.dns_domain);
392 printf(_("Domain Controller: %s\n"), reply.pdc_dns_name);
394 printf(_("Pre-Win2k Domain: %s\n"), reply.domain_name);
395 printf(_("Pre-Win2k Hostname: %s\n"), reply.pdc_name);
397 if (*reply.user_name) printf(_("User name: %s\n"), reply.user_name);
399 printf(_("Server Site Name: %s\n"), reply.server_site);
400 printf(_("Client Site Name: %s\n"), reply.client_site);
402 d_printf(_("NT Version: %d\n"), reply.nt_version);
403 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
404 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
410 this implements the CLDAP based netlogon lookup requests
411 for finding the domain controller of a ADS domain
413 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
418 if (c->display_usage) {
423 _("Find the ADS DC using CLDAP lookup.\n"));
427 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
428 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
433 if (!ads->config.realm) {
434 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
435 ads->ldap.port = 389;
438 ret = net_ads_cldap_netlogon(c, ads);
446 static int net_ads_info_json(ADS_STRUCT *ads)
449 char addr[INET6_ADDRSTRLEN];
451 struct json_object jsobj = json_new_object();
453 if (json_is_invalid(&jsobj)) {
454 d_fprintf(stderr, _("error setting up JSON value\n"));
459 pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
461 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
463 ret = json_add_string (&jsobj, "LDAP server", addr);
468 ret = json_add_string (&jsobj, "LDAP server name",
469 ads->config.ldap_server_name);
474 ret = json_add_string (&jsobj, "Realm", ads->config.realm);
479 ret = json_add_string (&jsobj, "Bind Path", ads->config.bind_path);
484 ret = json_add_int (&jsobj, "LDAP port", ads->ldap.port);
489 ret = json_add_int (&jsobj, "Server time", ads->config.current_time);
494 ret = json_add_string (&jsobj, "KDC server", ads->auth.kdc_server);
499 ret = json_add_int (&jsobj, "Server time offset",
500 ads->auth.time_offset);
505 ret = json_add_int (&jsobj, "Last machine account password change",
511 ret = output_json(&jsobj);
519 #else /* [HAVE_JANSSON] */
521 static int net_ads_info_json(ADS_STRUCT *ads)
523 d_fprintf(stderr, _("JSON support not available\n"));
528 #endif /* [HAVE_JANSSON] */
532 static int net_ads_info(struct net_context *c, int argc, const char **argv)
535 char addr[INET6_ADDRSTRLEN];
538 if (c->display_usage) {
543 _("Display information about an Active Directory "
548 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
549 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
553 if (!ads || !ads->config.realm) {
554 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
559 /* Try to set the server's current time since we didn't do a full
560 TCP LDAP session initially */
562 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
563 d_fprintf( stderr, _("Failed to get server's current time!\n"));
567 return net_ads_info_json(ads);
570 pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
572 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
574 d_printf(_("LDAP server: %s\n"), addr);
575 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
576 d_printf(_("Realm: %s\n"), ads->config.realm);
577 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
578 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
579 d_printf(_("Server time: %s\n"),
580 http_timestring(talloc_tos(), ads->config.current_time));
582 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
583 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
585 d_printf(_("Last machine account password change: %s\n"),
586 http_timestring(talloc_tos(), pass_time));
592 static void use_in_memory_ccache(void) {
593 /* Use in-memory credentials cache so we do not interfere with
594 * existing credentials */
595 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
598 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
599 uint32_t auth_flags, ADS_STRUCT **ads_ret)
601 ADS_STRUCT *ads = NULL;
603 bool need_password = false;
604 bool second_time = false;
606 const char *realm = NULL;
607 bool tried_closest_dc = false;
609 /* lp_realm() should be handled by a command line param,
610 However, the join requires that realm be set in smb.conf
611 and compares our realm with the remote server's so this is
612 ok until someone needs more flexibility */
617 if (only_own_domain) {
620 realm = assume_own_realm(c);
623 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
625 if (!c->opt_user_name) {
626 c->opt_user_name = "administrator";
629 if (c->opt_user_specified) {
630 need_password = true;
634 if (!c->opt_password && need_password && !c->opt_machine_pass) {
635 c->opt_password = net_prompt_pass(c, c->opt_user_name);
636 if (!c->opt_password) {
638 return ADS_ERROR(LDAP_NO_MEMORY);
642 if (c->opt_password) {
643 use_in_memory_ccache();
644 SAFE_FREE(ads->auth.password);
645 ads->auth.password = smb_xstrdup(c->opt_password);
648 ads->auth.flags |= auth_flags;
649 SAFE_FREE(ads->auth.user_name);
650 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
653 * If the username is of the form "name@realm",
654 * extract the realm and convert to upper case.
655 * This is only used to establish the connection.
657 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
659 SAFE_FREE(ads->auth.realm);
660 ads->auth.realm = smb_xstrdup(cp);
661 if (!strupper_m(ads->auth.realm)) {
663 return ADS_ERROR(LDAP_NO_MEMORY);
667 status = ads_connect(ads);
669 if (!ADS_ERR_OK(status)) {
671 if (NT_STATUS_EQUAL(ads_ntstatus(status),
672 NT_STATUS_NO_LOGON_SERVERS)) {
673 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
678 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
679 need_password = true;
688 /* when contacting our own domain, make sure we use the closest DC.
689 * This is done by reconnecting to ADS because only the first call to
690 * ads_connect will give us our own sitename */
692 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
694 tried_closest_dc = true; /* avoid loop */
696 if (!ads_closest_dc(ads)) {
698 namecache_delete(ads->server.realm, 0x1C);
699 namecache_delete(ads->server.workgroup, 0x1C);
712 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
714 return ads_startup_int(c, only_own_domain, 0, ads);
717 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
719 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
723 Check to see if connection can be made via ads.
724 ads_startup() stores the password in opt_password if it needs to so
725 that rpc or rap can use it without re-prompting.
727 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
732 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
736 ads->auth.flags |= ADS_AUTH_NO_BIND;
738 status = ads_connect(ads);
739 if ( !ADS_ERR_OK(status) ) {
747 int net_ads_check_our_domain(struct net_context *c)
749 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
752 int net_ads_check(struct net_context *c)
754 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
758 determine the netbios workgroup name for a domain
760 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
763 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
765 if (c->display_usage) {
767 "net ads workgroup\n"
770 _("Print the workgroup name"));
774 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
775 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
779 if (!ads->config.realm) {
780 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
781 ads->ldap.port = 389;
784 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
785 d_fprintf(stderr, _("CLDAP query failed!\n"));
790 d_printf(_("Workgroup: %s\n"), reply.domain_name);
799 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
801 char **disp_fields = (char **) data_area;
803 if (!field) { /* must be end of record */
804 if (disp_fields[0]) {
805 if (!strchr_m(disp_fields[0], '$')) {
807 d_printf("%-21.21s %s\n",
808 disp_fields[0], disp_fields[1]);
810 d_printf("%s\n", disp_fields[0]);
813 SAFE_FREE(disp_fields[0]);
814 SAFE_FREE(disp_fields[1]);
817 if (!values) /* must be new field, indicate string field */
819 if (strcasecmp_m(field, "sAMAccountName") == 0) {
820 disp_fields[0] = SMB_STRDUP((char *) values[0]);
822 if (strcasecmp_m(field, "description") == 0)
823 disp_fields[1] = SMB_STRDUP((char *) values[0]);
827 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
829 return net_user_usage(c, argc, argv);
832 static int ads_user_add(struct net_context *c, int argc, const char **argv)
837 LDAPMessage *res=NULL;
841 if (argc < 1 || c->display_usage)
842 return net_ads_user_usage(c, argc, argv);
844 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
848 status = ads_find_user_acct(ads, &res, argv[0]);
850 if (!ADS_ERR_OK(status)) {
851 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
855 if (ads_count_replies(ads, res)) {
856 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
861 if (c->opt_container) {
862 ou_str = SMB_STRDUP(c->opt_container);
864 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
867 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
869 if (!ADS_ERR_OK(status)) {
870 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
875 /* if no password is to be set, we're done */
877 d_printf(_("User %s added\n"), argv[0]);
882 /* try setting the password */
883 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
886 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
887 ads->auth.time_offset);
889 if (ADS_ERR_OK(status)) {
890 d_printf(_("User %s added\n"), argv[0]);
895 /* password didn't set, delete account */
896 d_fprintf(stderr, _("Could not add user %s. "
897 "Error setting password %s\n"),
898 argv[0], ads_errstr(status));
899 ads_msgfree(ads, res);
900 status=ads_find_user_acct(ads, &res, argv[0]);
901 if (ADS_ERR_OK(status)) {
902 userdn = ads_get_dn(ads, talloc_tos(), res);
903 ads_del_dn(ads, userdn);
909 ads_msgfree(ads, res);
915 static int ads_user_info(struct net_context *c, int argc, const char **argv)
917 ADS_STRUCT *ads = NULL;
919 LDAPMessage *res = NULL;
923 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
924 char *searchstring=NULL;
928 struct dom_sid primary_group_sid;
930 enum wbcSidType type;
932 if (argc < 1 || c->display_usage) {
933 return net_ads_user_usage(c, argc, argv);
936 frame = talloc_new(talloc_tos());
941 escaped_user = escape_ldap_string(frame, argv[0]);
944 _("ads_user_info: failed to escape user %s\n"),
949 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
954 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
958 rc = ads_search(ads, &res, searchstring, attrs);
959 SAFE_FREE(searchstring);
961 if (!ADS_ERR_OK(rc)) {
962 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
967 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
968 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
973 rc = ads_domain_sid(ads, &primary_group_sid);
974 if (!ADS_ERR_OK(rc)) {
975 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
980 sid_append_rid(&primary_group_sid, group_rid);
982 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
983 NULL, /* don't look up domain */
986 if (!WBC_ERROR_IS_OK(wbc_status)) {
987 d_fprintf(stderr, "wbcLookupSid: %s\n",
988 wbcErrorString(wbc_status));
993 d_printf("%s\n", primary_group);
995 wbcFreeMemory(primary_group);
997 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
998 (LDAPMessage *)res, "memberOf");
1003 for (i=0;grouplist[i];i++) {
1004 groupname = ldap_explode_dn(grouplist[i], 1);
1005 d_printf("%s\n", groupname[0]);
1006 ldap_value_free(groupname);
1008 ldap_value_free(grouplist);
1012 if (res) ads_msgfree(ads, res);
1013 if (ads) ads_destroy(&ads);
1018 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
1022 LDAPMessage *res = NULL;
1026 return net_ads_user_usage(c, argc, argv);
1029 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1033 rc = ads_find_user_acct(ads, &res, argv[0]);
1034 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
1035 d_printf(_("User %s does not exist.\n"), argv[0]);
1036 ads_msgfree(ads, res);
1040 userdn = ads_get_dn(ads, talloc_tos(), res);
1041 ads_msgfree(ads, res);
1042 rc = ads_del_dn(ads, userdn);
1043 TALLOC_FREE(userdn);
1044 if (ADS_ERR_OK(rc)) {
1045 d_printf(_("User %s deleted\n"), argv[0]);
1049 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
1055 int net_ads_user(struct net_context *c, int argc, const char **argv)
1057 struct functable func[] = {
1062 N_("Add an AD user"),
1063 N_("net ads user add\n"
1070 N_("Display information about an AD user"),
1071 N_("net ads user info\n"
1072 " Display information about an AD user")
1078 N_("Delete an AD user"),
1079 N_("net ads user delete\n"
1080 " Delete an AD user")
1082 {NULL, NULL, 0, NULL, NULL}
1086 const char *shortattrs[] = {"sAMAccountName", NULL};
1087 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1088 char *disp_fields[2] = {NULL, NULL};
1091 if (c->display_usage) {
1096 _("List AD users"));
1097 net_display_usage_from_functable(func);
1101 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1105 if (c->opt_long_list_entries)
1106 d_printf(_("\nUser name Comment"
1107 "\n-----------------------------\n"));
1109 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
1111 "(objectCategory=user)",
1112 c->opt_long_list_entries ? longattrs :
1113 shortattrs, usergrp_display,
1116 return ADS_ERR_OK(rc) ? 0 : -1;
1119 return net_run_function(c, argc, argv, "net ads user", func);
1122 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
1124 return net_group_usage(c, argc, argv);
1127 static int ads_group_add(struct net_context *c, int argc, const char **argv)
1131 LDAPMessage *res=NULL;
1133 char *ou_str = NULL;
1135 if (argc < 1 || c->display_usage) {
1136 return net_ads_group_usage(c, argc, argv);
1139 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1143 status = ads_find_user_acct(ads, &res, argv[0]);
1145 if (!ADS_ERR_OK(status)) {
1146 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
1150 if (ads_count_replies(ads, res)) {
1151 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
1155 if (c->opt_container) {
1156 ou_str = SMB_STRDUP(c->opt_container);
1158 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
1161 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
1163 if (ADS_ERR_OK(status)) {
1164 d_printf(_("Group %s added\n"), argv[0]);
1167 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
1168 ads_errstr(status));
1173 ads_msgfree(ads, res);
1179 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
1183 LDAPMessage *res = NULL;
1186 if (argc < 1 || c->display_usage) {
1187 return net_ads_group_usage(c, argc, argv);
1190 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1194 rc = ads_find_user_acct(ads, &res, argv[0]);
1195 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
1196 d_printf(_("Group %s does not exist.\n"), argv[0]);
1197 ads_msgfree(ads, res);
1201 groupdn = ads_get_dn(ads, talloc_tos(), res);
1202 ads_msgfree(ads, res);
1203 rc = ads_del_dn(ads, groupdn);
1204 TALLOC_FREE(groupdn);
1205 if (ADS_ERR_OK(rc)) {
1206 d_printf(_("Group %s deleted\n"), argv[0]);
1210 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
1216 int net_ads_group(struct net_context *c, int argc, const char **argv)
1218 struct functable func[] = {
1223 N_("Add an AD group"),
1224 N_("net ads group add\n"
1231 N_("Delete an AD group"),
1232 N_("net ads group delete\n"
1233 " Delete an AD group")
1235 {NULL, NULL, 0, NULL, NULL}
1239 const char *shortattrs[] = {"sAMAccountName", NULL};
1240 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1241 char *disp_fields[2] = {NULL, NULL};
1244 if (c->display_usage) {
1249 _("List AD groups"));
1250 net_display_usage_from_functable(func);
1254 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1258 if (c->opt_long_list_entries)
1259 d_printf(_("\nGroup name Comment"
1260 "\n-----------------------------\n"));
1261 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
1263 "(objectCategory=group)",
1264 c->opt_long_list_entries ? longattrs :
1265 shortattrs, usergrp_display,
1269 return ADS_ERR_OK(rc) ? 0 : -1;
1271 return net_run_function(c, argc, argv, "net ads group", func);
1274 static int net_ads_status(struct net_context *c, int argc, const char **argv)
1280 if (c->display_usage) {
1285 _("Display machine account details"));
1289 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1293 rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
1294 if (!ADS_ERR_OK(rc)) {
1295 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
1300 if (ads_count_replies(ads, res) == 0) {
1301 d_fprintf(stderr, _("No machine account for '%s' found\n"), lp_netbios_name());
1311 /*******************************************************************
1312 Leave an AD domain. Windows XP disables the machine account.
1313 We'll try the same. The old code would do an LDAP delete.
1314 That only worked using the machine creds because added the machine
1315 with full control to the computer object's ACL.
1316 *******************************************************************/
1318 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
1321 struct libnet_UnjoinCtx *r = NULL;
1324 if (c->display_usage) {
1326 "net ads leave [--keep-account]\n"
1329 _("Leave an AD domain"));
1334 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
1338 if (!(ctx = talloc_init("net_ads_leave"))) {
1339 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1343 if (!c->opt_kerberos) {
1344 use_in_memory_ccache();
1348 d_fprintf(stderr, _("Could not initialise message context. "
1349 "Try running as root\n"));
1353 werr = libnet_init_UnjoinCtx(ctx, &r);
1354 if (!W_ERROR_IS_OK(werr)) {
1355 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
1360 r->in.use_kerberos = c->opt_kerberos;
1361 r->in.dc_name = c->opt_host;
1362 r->in.domain_name = lp_realm();
1363 r->in.admin_account = c->opt_user_name;
1364 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1365 r->in.modify_config = lp_config_backend_is_registry();
1367 /* Try to delete it, but if that fails, disable it. The
1368 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1369 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1370 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1371 if (c->opt_keep_account) {
1372 r->in.delete_machine_account = false;
1374 r->in.delete_machine_account = true;
1377 r->in.msg_ctx = c->msg_ctx;
1379 werr = libnet_Unjoin(ctx, r);
1380 if (!W_ERROR_IS_OK(werr)) {
1381 d_printf(_("Failed to leave domain: %s\n"),
1382 r->out.error_string ? r->out.error_string :
1383 get_friendly_werror_msg(werr));
1387 if (r->out.deleted_machine_account) {
1388 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1389 r->in.machine_name, r->out.dns_domain_name);
1393 /* We couldn't delete it - see if the disable succeeded. */
1394 if (r->out.disabled_machine_account) {
1395 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1396 r->in.machine_name, r->out.dns_domain_name);
1401 /* Based on what we requested, we shouldn't get here, but if
1402 we did, it means the secrets were removed, and therefore
1403 we have left the domain */
1404 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1405 r->in.machine_name, r->out.dns_domain_name);
1411 if (W_ERROR_IS_OK(werr)) {
1418 static NTSTATUS net_ads_join_ok(struct net_context *c)
1420 ADS_STRUCT *ads = NULL;
1423 struct sockaddr_storage dcip;
1425 if (!secrets_init()) {
1426 DEBUG(1,("Failed to initialise secrets database\n"));
1427 return NT_STATUS_ACCESS_DENIED;
1430 net_use_krb_machine_account(c);
1432 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1434 status = ads_startup(c, true, &ads);
1435 if (!ADS_ERR_OK(status)) {
1436 return ads_ntstatus(status);
1440 return NT_STATUS_OK;
1444 check that an existing join is OK
1446 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1449 use_in_memory_ccache();
1451 if (c->display_usage) {
1453 "net ads testjoin\n"
1456 _("Test if the existing join is ok"));
1460 /* Display success or failure */
1461 status = net_ads_join_ok(c);
1462 if (!NT_STATUS_IS_OK(status)) {
1463 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1464 get_friendly_nt_error_msg(status));
1468 printf(_("Join is OK\n"));
1472 /*******************************************************************
1473 Simple configu checks before beginning the join
1474 ********************************************************************/
1476 static WERROR check_ads_config( void )
1478 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1479 d_printf(_("Host is not configured as a member server.\n"));
1480 return WERR_INVALID_DOMAIN_ROLE;
1483 if (strlen(lp_netbios_name()) > 15) {
1484 d_printf(_("Our netbios name can be at most 15 chars long, "
1485 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1486 (unsigned int)strlen(lp_netbios_name()));
1487 return WERR_INVALID_COMPUTERNAME;
1490 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1491 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1492 "join to succeed.\n"), get_dyn_CONFIGFILE());
1493 return WERR_INVALID_PARAMETER;
1499 /*******************************************************************
1500 Send a DNS update request
1501 *******************************************************************/
1503 #if defined(WITH_DNS_UPDATES)
1504 #include "../lib/addns/dns.h"
1506 static NTSTATUS net_update_dns_internal(struct net_context *c,
1507 TALLOC_CTX *ctx, ADS_STRUCT *ads,
1508 const char *machine_name,
1509 const struct sockaddr_storage *addrs,
1510 int num_addrs, bool remove_host)
1512 struct dns_rr_ns *nameservers = NULL;
1513 int ns_count = 0, i;
1514 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1517 const char *dnsdomain = NULL;
1518 char *root_domain = NULL;
1520 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1521 d_printf(_("No DNS domain configured for %s. "
1522 "Unable to perform DNS Update.\n"), machine_name);
1523 status = NT_STATUS_INVALID_PARAMETER;
1528 status = ads_dns_lookup_ns(ctx,
1532 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1533 /* Child domains often do not have NS records. Look
1534 for the NS record for the forest root domain
1535 (rootDomainNamingContext in therootDSE) */
1537 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1538 LDAPMessage *msg = NULL;
1540 ADS_STATUS ads_status;
1542 if ( !ads->ldap.ld ) {
1543 ads_status = ads_connect( ads );
1544 if ( !ADS_ERR_OK(ads_status) ) {
1545 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1550 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1551 "(objectclass=*)", rootname_attrs, &msg);
1552 if (!ADS_ERR_OK(ads_status)) {
1556 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1558 ads_msgfree( ads, msg );
1562 root_domain = ads_build_domain( root_dn );
1565 ads_msgfree( ads, msg );
1567 /* try again for NS servers */
1569 status = ads_dns_lookup_ns(ctx,
1574 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1575 DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
1576 "realm\n", ads->config.realm));
1577 if (ns_count == 0) {
1578 status = NT_STATUS_UNSUCCESSFUL;
1583 dnsdomain = root_domain;
1587 for (i=0; i < ns_count; i++) {
1589 uint32_t flags = DNS_UPDATE_SIGNED |
1590 DNS_UPDATE_UNSIGNED |
1591 DNS_UPDATE_UNSIGNED_SUFFICIENT |
1593 DNS_UPDATE_PROBE_SUFFICIENT;
1596 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
1597 flags &= ~DNS_UPDATE_UNSIGNED_SUFFICIENT;
1601 * Do not return after PROBE completion if this function
1602 * is called for DNS removal.
1605 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
1608 status = NT_STATUS_UNSUCCESSFUL;
1610 /* Now perform the dns update - we'll try non-secure and if we fail,
1611 we'll follow it up with a secure update */
1613 fstrcpy( dns_server, nameservers[i].hostname );
1615 dns_err = DoDNSUpdate(dns_server,
1622 if (ERR_DNS_IS_OK(dns_err)) {
1623 status = NT_STATUS_OK;
1627 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
1628 ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
1629 ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
1630 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1631 dns_errstr(dns_err)));
1635 d_printf(_("DNS Update for %s failed: %s\n"),
1636 machine_name, dns_errstr(dns_err));
1637 status = NT_STATUS_UNSUCCESSFUL;
1643 SAFE_FREE( root_domain );
1648 static NTSTATUS net_update_dns_ext(struct net_context *c,
1649 TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1650 const char *hostname,
1651 struct sockaddr_storage *iplist,
1652 int num_addrs, bool remove_host)
1654 struct sockaddr_storage *iplist_alloc = NULL;
1655 fstring machine_name;
1659 fstrcpy(machine_name, hostname);
1661 name_to_fqdn( machine_name, lp_netbios_name() );
1663 if (!strlower_m( machine_name )) {
1664 return NT_STATUS_INVALID_PARAMETER;
1668 * If remove_host is true, then remove all IP addresses associated with
1669 * this hostname from the AD server.
1671 if (!remove_host && (num_addrs == 0 || iplist == NULL)) {
1673 * Get our ip address
1674 * (not the 127.0.0.x address but a real ip address)
1676 num_addrs = get_my_ip_address(&iplist_alloc);
1677 if ( num_addrs <= 0 ) {
1678 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1679 "non-loopback IP addresses!\n"));
1680 return NT_STATUS_INVALID_PARAMETER;
1682 iplist = iplist_alloc;
1685 status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
1686 iplist, num_addrs, remove_host);
1688 SAFE_FREE(iplist_alloc);
1692 static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1696 status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0, false);
1702 /*******************************************************************
1703 ********************************************************************/
1705 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1707 d_printf(_("net ads join [--no-dns-updates] [options]\n"
1708 "Valid options:\n"));
1709 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1710 " The default UPN is in the form host/netbiosname@REALM.\n"));
1711 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1712 " The OU string read from top to bottom without RDNs\n"
1713 " and delimited by a '/'.\n"
1714 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1715 " NB: A backslash '\\' is used as escape at multiple\n"
1716 " levels and may need to be doubled or even\n"
1717 " quadrupled. It is not used as a separator.\n"));
1718 d_printf(_(" machinepass=PASS Set the machine password to a specific value during\n"
1719 " the join. The default password is random.\n"));
1720 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1721 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during join.\n"
1722 " NB: osName and osVer must be specified together for\n"
1723 " either to take effect. The operatingSystemService\n"
1724 " attribute is then also set along with the two\n"
1725 " other attributes.\n"));
1726 d_printf(_(" osServicePack=string Set the operatingSystemServicePack attribute\n"
1727 " during the join.\n"
1728 " NB: If not specified then by default the samba\n"
1729 " version string is used instead.\n"));
1734 static void _net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
1736 #if defined(WITH_DNS_UPDATES)
1737 ADS_STRUCT *ads_dns = NULL;
1742 * In a clustered environment, don't do dynamic dns updates:
1743 * Registering the set of ip addresses that are assigned to
1744 * the interfaces of the node that performs the join does usually
1745 * not have the desired effect, since the local interfaces do not
1746 * carry the complete set of the cluster's public IP addresses.
1747 * And it can also contain internal addresses that should not
1748 * be visible to the outside at all.
1749 * In order to do dns updates in a clustererd setup, use
1750 * net ads dns register.
1752 if (lp_clustering()) {
1753 d_fprintf(stderr, _("Not doing automatic DNS update in a "
1754 "clustered setup.\n"));
1758 if (!r->out.domain_is_ad) {
1763 * We enter this block with user creds.
1764 * kinit with the machine password to do dns update.
1767 ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name);
1769 if (ads_dns == NULL) {
1770 d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
1774 use_in_memory_ccache();
1776 ret = asprintf(&ads_dns->auth.user_name, "%s$", lp_netbios_name());
1778 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1782 ads_dns->auth.password = secrets_fetch_machine_password(
1783 r->out.netbios_domain_name, NULL, NULL);
1784 if (ads_dns->auth.password == NULL) {
1785 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1789 ads_dns->auth.realm = SMB_STRDUP(r->out.dns_domain_name);
1790 if (ads_dns->auth.realm == NULL) {
1791 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1795 if (!strupper_m(ads_dns->auth.realm)) {
1796 d_fprintf(stderr, _("strupper_m %s failed\n"), ads_dns->auth.realm);
1800 ret = ads_kinit_password(ads_dns);
1803 _("DNS update failed: kinit failed: %s\n"),
1804 error_message(ret));
1808 status = net_update_dns(c, ctx, ads_dns, NULL);
1809 if (!NT_STATUS_IS_OK(status)) {
1810 d_fprintf( stderr, _("DNS update failed: %s\n"),
1815 ads_destroy(&ads_dns);
1822 int net_ads_join(struct net_context *c, int argc, const char **argv)
1824 TALLOC_CTX *ctx = NULL;
1825 struct libnet_JoinCtx *r = NULL;
1826 const char *domain = lp_realm();
1827 WERROR werr = WERR_NERR_SETUPNOTJOINED;
1828 bool createupn = false;
1829 const char *machineupn = NULL;
1830 const char *machine_password = NULL;
1831 const char *create_in_ou = NULL;
1833 const char *os_name = NULL;
1834 const char *os_version = NULL;
1835 const char *os_servicepack = NULL;
1836 bool modify_config = lp_config_backend_is_registry();
1837 enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1839 if (c->display_usage)
1840 return net_ads_join_usage(c, argc, argv);
1842 if (!modify_config) {
1844 werr = check_ads_config();
1845 if (!W_ERROR_IS_OK(werr)) {
1846 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1851 if (!(ctx = talloc_init("net_ads_join"))) {
1852 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1853 werr = WERR_NOT_ENOUGH_MEMORY;
1857 if (!c->opt_kerberos) {
1858 use_in_memory_ccache();
1861 werr = libnet_init_JoinCtx(ctx, &r);
1862 if (!W_ERROR_IS_OK(werr)) {
1866 /* process additional command line args */
1868 for ( i=0; i<argc; i++ ) {
1869 if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1871 machineupn = get_string_param(argv[i]);
1873 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1874 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1875 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1876 werr = WERR_INVALID_PARAMETER;
1880 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1881 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1882 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1883 werr = WERR_INVALID_PARAMETER;
1887 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1888 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1889 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1890 werr = WERR_INVALID_PARAMETER;
1894 else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1895 if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1896 d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1897 werr = WERR_INVALID_PARAMETER;
1901 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1902 if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1903 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1904 werr = WERR_INVALID_PARAMETER;
1910 if (strchr(domain, '.') == NULL) {
1911 domain_name_type = JoinDomNameTypeUnknown;
1913 domain_name_type = JoinDomNameTypeDNS;
1919 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1920 werr = WERR_INVALID_PARAMETER;
1925 d_fprintf(stderr, _("Could not initialise message context. "
1926 "Try running as root\n"));
1927 werr = WERR_ACCESS_DENIED;
1931 /* Do the domain join here */
1933 r->in.domain_name = domain;
1934 r->in.domain_name_type = domain_name_type;
1935 r->in.create_upn = createupn;
1936 r->in.upn = machineupn;
1937 r->in.account_ou = create_in_ou;
1938 r->in.os_name = os_name;
1939 r->in.os_version = os_version;
1940 r->in.os_servicepack = os_servicepack;
1941 r->in.dc_name = c->opt_host;
1942 r->in.admin_account = c->opt_user_name;
1943 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1944 r->in.machine_password = machine_password;
1946 r->in.use_kerberos = c->opt_kerberos;
1947 r->in.modify_config = modify_config;
1948 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1949 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1950 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1951 r->in.msg_ctx = c->msg_ctx;
1953 werr = libnet_Join(ctx, r);
1954 if (W_ERROR_EQUAL(werr, WERR_NERR_DCNOTFOUND) &&
1955 strequal(domain, lp_realm())) {
1956 r->in.domain_name = lp_workgroup();
1957 r->in.domain_name_type = JoinDomNameTypeNBT;
1958 werr = libnet_Join(ctx, r);
1960 if (!W_ERROR_IS_OK(werr)) {
1964 /* Check the short name of the domain */
1966 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1967 d_printf(_("The workgroup in %s does not match the short\n"
1968 "domain name obtained from the server.\n"
1969 "Using the name [%s] from the server.\n"
1970 "You should set \"workgroup = %s\" in %s.\n"),
1971 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1972 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1975 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1977 if (r->out.dns_domain_name) {
1978 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1979 r->out.dns_domain_name);
1981 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1982 r->out.netbios_domain_name);
1985 /* print out informative error string in case there is one */
1986 if (r->out.error_string != NULL) {
1987 d_printf("%s\n", r->out.error_string);
1991 * We try doing the dns update (if it was compiled in
1992 * and if it was not disabled on the command line).
1993 * If the dns update fails, we still consider the join
1994 * operation as succeeded if we came this far.
1996 if (!c->opt_no_dns_updates) {
1997 _net_ads_join_dns_updates(c, ctx, r);
2006 /* issue an overall failure message at the end. */
2007 d_printf(_("Failed to join domain: %s\n"),
2008 r && r->out.error_string ? r->out.error_string :
2009 get_friendly_werror_msg(werr));
2015 /*******************************************************************
2016 ********************************************************************/
2018 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
2020 #if defined(WITH_DNS_UPDATES)
2025 const char *hostname = NULL;
2026 const char **addrs_list = NULL;
2027 struct sockaddr_storage *addrs = NULL;
2032 talloc_enable_leak_report();
2035 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
2036 d_fprintf(stderr, _("Refusing DNS updates with automatic "
2037 "detection of addresses in a clustered "
2039 c->display_usage = true;
2042 if (c->display_usage) {
2044 "net ads dns register [hostname [IP [IP...]]]\n"
2047 _("Register hostname with DNS\n"));
2051 if (!(ctx = talloc_init("net_ads_dns"))) {
2052 d_fprintf(stderr, _("Could not initialise talloc context\n"));
2061 num_addrs = argc - 1;
2062 addrs_list = &argv[1];
2063 } else if (lp_clustering()) {
2064 addrs_list = lp_cluster_addresses();
2065 num_addrs = str_list_length(addrs_list);
2068 if (num_addrs > 0) {
2069 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
2070 if (addrs == NULL) {
2071 d_fprintf(stderr, _("Error allocating memory!\n"));
2077 for (count = 0; count < num_addrs; count++) {
2078 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
2079 d_fprintf(stderr, "%s '%s'.\n",
2080 _("Cannot interpret address"),
2087 status = ads_startup(c, true, &ads);
2088 if ( !ADS_ERR_OK(status) ) {
2089 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
2094 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs, false);
2095 if (!NT_STATUS_IS_OK(ntstatus)) {
2096 d_fprintf( stderr, _("DNS update failed!\n") );
2097 ads_destroy( &ads );
2102 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
2110 _("DNS update support not enabled at compile time!\n"));
2115 static int net_ads_dns_unregister(struct net_context *c,
2119 #if defined(WITH_DNS_UPDATES)
2124 const char *hostname = NULL;
2127 talloc_enable_leak_report();
2131 c->display_usage = true;
2134 if (c->display_usage) {
2136 "net ads dns unregister [hostname]\n"
2139 _("Register hostname with DNS\n"));
2143 if (!(ctx = talloc_init("net_ads_dns"))) {
2144 d_fprintf(stderr, _("Could not initialise talloc context\n"));
2148 /* Get the hostname for un-registering */
2151 status = ads_startup(c, true, &ads);
2152 if ( !ADS_ERR_OK(status) ) {
2153 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
2158 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, NULL, 0, true);
2159 if (!NT_STATUS_IS_OK(ntstatus)) {
2160 d_fprintf( stderr, _("DNS update failed!\n") );
2161 ads_destroy( &ads );
2166 d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
2174 _("DNS update support not enabled at compile time!\n"));
2179 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
2181 #if defined(WITH_DNS_UPDATES)
2185 talloc_enable_leak_report();
2188 if (argc != 2 || c->display_usage) {
2193 _("net ads dns gethostbyname <server> <name>\n"),
2194 _(" Look up hostname from the AD\n"
2195 " server\tName server to use\n"
2196 " name\tName to look up\n"));
2200 err = do_gethostbyname(argv[0], argv[1]);
2201 if (!ERR_DNS_IS_OK(err)) {
2202 d_printf(_("do_gethostbyname returned %s (%d)\n"),
2203 dns_errstr(err), ERROR_DNS_V(err));
2209 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
2211 struct functable func[] = {
2214 net_ads_dns_register,
2216 N_("Add host dns entry to AD"),
2217 N_("net ads dns register\n"
2218 " Add host dns entry to AD")
2222 net_ads_dns_unregister,
2224 N_("Remove host dns entry from AD"),
2225 N_("net ads dns unregister\n"
2226 " Remove host dns entry from AD")
2230 net_ads_dns_gethostbyname,
2233 N_("net ads dns gethostbyname\n"
2236 {NULL, NULL, 0, NULL, NULL}
2239 return net_run_function(c, argc, argv, "net ads dns", func);
2242 /*******************************************************************
2243 ********************************************************************/
2245 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
2248 "\nnet ads printer search <printer>"
2249 "\n\tsearch for a printer in the directory\n"
2250 "\nnet ads printer info <printer> <server>"
2251 "\n\tlookup info in directory for printer on server"
2252 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2253 "\nnet ads printer publish <printername>"
2254 "\n\tpublish printer in directory"
2255 "\n\t(note: printer name is required)\n"
2256 "\nnet ads printer remove <printername>"
2257 "\n\tremove printer from directory"
2258 "\n\t(note: printer name is required)\n"));
2262 /*******************************************************************
2263 ********************************************************************/
2265 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
2269 LDAPMessage *res = NULL;
2271 if (c->display_usage) {
2273 "net ads printer search\n"
2276 _("List printers in the AD"));
2280 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2284 rc = ads_find_printers(ads, &res);
2286 if (!ADS_ERR_OK(rc)) {
2287 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
2288 ads_msgfree(ads, res);
2293 if (ads_count_replies(ads, res) == 0) {
2294 d_fprintf(stderr, _("No results found\n"));
2295 ads_msgfree(ads, res);
2301 ads_msgfree(ads, res);
2306 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
2310 const char *servername, *printername;
2311 LDAPMessage *res = NULL;
2313 if (c->display_usage) {
2316 _("net ads printer info [printername [servername]]\n"
2317 " Display printer info from AD\n"
2318 " printername\tPrinter name or wildcard\n"
2319 " servername\tName of the print server\n"));
2323 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2328 printername = argv[0];
2334 servername = argv[1];
2336 servername = lp_netbios_name();
2339 rc = ads_find_printer_on_server(ads, &res, printername, servername);
2341 if (!ADS_ERR_OK(rc)) {
2342 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
2343 servername, ads_errstr(rc));
2344 ads_msgfree(ads, res);
2349 if (ads_count_replies(ads, res) == 0) {
2350 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
2351 ads_msgfree(ads, res);
2357 ads_msgfree(ads, res);
2363 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
2367 const char *servername, *printername;
2368 struct cli_state *cli = NULL;
2369 struct rpc_pipe_client *pipe_hnd = NULL;
2370 struct sockaddr_storage server_ss;
2372 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
2373 ADS_MODLIST mods = ads_init_mods(mem_ctx);
2374 char *prt_dn, *srv_dn, **srv_cn;
2375 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
2376 LDAPMessage *res = NULL;
2379 if (argc < 1 || c->display_usage) {
2382 _("net ads printer publish <printername> [servername]\n"
2383 " Publish printer in AD\n"
2384 " printername\tName of the printer\n"
2385 " servername\tName of the print server\n"));
2386 talloc_destroy(mem_ctx);
2390 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2391 talloc_destroy(mem_ctx);
2395 printername = argv[0];
2398 servername = argv[1];
2400 servername = lp_netbios_name();
2403 /* Get printer data from SPOOLSS */
2405 ok = resolve_name(servername, &server_ss, 0x20, false);
2407 d_fprintf(stderr, _("Could not find server %s\n"),
2410 talloc_destroy(mem_ctx);
2414 nt_status = cli_full_connection(&cli, lp_netbios_name(), servername,
2417 c->opt_user_name, c->opt_workgroup,
2418 c->opt_password ? c->opt_password : "",
2419 CLI_FULL_CONNECTION_USE_KERBEROS,
2420 SMB_SIGNING_IPC_DEFAULT);
2422 if (NT_STATUS_IS_ERR(nt_status)) {
2423 d_fprintf(stderr, _("Unable to open a connection to %s to "
2424 "obtain data for %s\n"),
2425 servername, printername);
2427 talloc_destroy(mem_ctx);
2431 /* Publish on AD server */
2433 ads_find_machine_acct(ads, &res, servername);
2435 if (ads_count_replies(ads, res) == 0) {
2436 d_fprintf(stderr, _("Could not find machine account for server "
2440 talloc_destroy(mem_ctx);
2444 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2445 srv_cn = ldap_explode_dn(srv_dn, 1);
2447 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2448 printername_escaped = escape_rdn_val_string_alloc(printername);
2449 if (!srv_cn_escaped || !printername_escaped) {
2450 SAFE_FREE(srv_cn_escaped);
2451 SAFE_FREE(printername_escaped);
2452 d_fprintf(stderr, _("Internal error, out of memory!"));
2454 talloc_destroy(mem_ctx);
2458 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
2459 SAFE_FREE(srv_cn_escaped);
2460 SAFE_FREE(printername_escaped);
2461 d_fprintf(stderr, _("Internal error, out of memory!"));
2463 talloc_destroy(mem_ctx);
2467 SAFE_FREE(srv_cn_escaped);
2468 SAFE_FREE(printername_escaped);
2470 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2471 if (!NT_STATUS_IS_OK(nt_status)) {
2472 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2476 talloc_destroy(mem_ctx);
2480 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
2484 talloc_destroy(mem_ctx);
2488 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
2489 if (!ADS_ERR_OK(rc)) {
2490 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
2493 talloc_destroy(mem_ctx);
2497 d_printf("published printer\n");
2500 talloc_destroy(mem_ctx);
2505 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
2509 const char *servername;
2511 LDAPMessage *res = NULL;
2513 if (argc < 1 || c->display_usage) {
2516 _("net ads printer remove <printername> [servername]\n"
2517 " Remove a printer from the AD\n"
2518 " printername\tName of the printer\n"
2519 " servername\tName of the print server\n"));
2523 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2528 servername = argv[1];
2530 servername = lp_netbios_name();
2533 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2535 if (!ADS_ERR_OK(rc)) {
2536 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2537 ads_msgfree(ads, res);
2542 if (ads_count_replies(ads, res) == 0) {
2543 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2544 ads_msgfree(ads, res);
2549 prt_dn = ads_get_dn(ads, talloc_tos(), res);
2550 ads_msgfree(ads, res);
2551 rc = ads_del_dn(ads, prt_dn);
2552 TALLOC_FREE(prt_dn);
2554 if (!ADS_ERR_OK(rc)) {
2555 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2564 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2566 struct functable func[] = {
2569 net_ads_printer_search,
2571 N_("Search for a printer"),
2572 N_("net ads printer search\n"
2573 " Search for a printer")
2577 net_ads_printer_info,
2579 N_("Display printer information"),
2580 N_("net ads printer info\n"
2581 " Display printer information")
2585 net_ads_printer_publish,
2587 N_("Publish a printer"),
2588 N_("net ads printer publish\n"
2589 " Publish a printer")
2593 net_ads_printer_remove,
2595 N_("Delete a printer"),
2596 N_("net ads printer remove\n"
2597 " Delete a printer")
2599 {NULL, NULL, 0, NULL, NULL}
2602 return net_run_function(c, argc, argv, "net ads printer", func);
2606 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2609 const char *auth_principal = c->opt_user_name;
2610 const char *auth_password = c->opt_password;
2611 const char *realm = NULL;
2612 const char *new_password = NULL;
2615 char pwd[256] = {0};
2618 if (c->display_usage) {
2621 _("net ads password <username>\n"
2622 " Change password for user\n"
2623 " username\tName of user to change password for\n"));
2627 if (c->opt_user_name == NULL || c->opt_password == NULL) {
2628 d_fprintf(stderr, _("You must supply an administrator "
2629 "username/password\n"));
2634 d_fprintf(stderr, _("ERROR: You must say which username to "
2635 "change password for\n"));
2640 if (!strchr_m(user, '@')) {
2641 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2647 use_in_memory_ccache();
2648 chr = strchr_m(auth_principal, '@');
2655 /* use the realm so we can eventually change passwords for users
2656 in realms other than default */
2657 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
2661 /* we don't actually need a full connect, but it's the easy way to
2662 fill in the KDC's addresss */
2665 if (!ads->config.realm) {
2666 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2672 new_password = (const char *)argv[1];
2676 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2679 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2687 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2688 auth_password, user, new_password, ads->auth.time_offset);
2689 memset(pwd, '\0', sizeof(pwd));
2690 if (!ADS_ERR_OK(ret)) {
2691 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2696 d_printf(_("Password change for %s completed.\n"), user);
2702 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2705 char *host_principal;
2709 if (c->display_usage) {
2711 "net ads changetrustpw\n"
2714 _("Change the machine account's trust password"));
2718 if (!secrets_init()) {
2719 DEBUG(1,("Failed to initialise secrets database\n"));
2723 net_use_krb_machine_account(c);
2725 use_in_memory_ccache();
2727 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2731 fstrcpy(my_name, lp_netbios_name());
2732 if (!strlower_m(my_name)) {
2737 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2741 d_printf(_("Changing password for principal: %s\n"), host_principal);
2743 ret = ads_change_trust_account_password(ads, host_principal);
2745 if (!ADS_ERR_OK(ret)) {
2746 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2748 SAFE_FREE(host_principal);
2752 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2754 if (USE_SYSTEM_KEYTAB) {
2755 d_printf(_("Attempting to update system keytab with new password.\n"));
2756 if (ads_keytab_create_default(ads)) {
2757 d_printf(_("Failed to update system keytab.\n"));
2762 SAFE_FREE(host_principal);
2768 help for net ads search
2770 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2773 "\nnet ads search <expression> <attributes...>\n"
2774 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2775 "The expression is a standard LDAP search expression, and the\n"
2776 "attributes are a list of LDAP fields to show in the results.\n\n"
2777 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2779 net_common_flags_usage(c, argc, argv);
2785 general ADS search function. Useful in diagnosing problems in ADS
2787 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2791 const char *ldap_exp;
2793 LDAPMessage *res = NULL;
2795 if (argc < 1 || c->display_usage) {
2796 return net_ads_search_usage(c, argc, argv);
2799 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2806 rc = ads_do_search_retry(ads, ads->config.bind_path,
2808 ldap_exp, attrs, &res);
2809 if (!ADS_ERR_OK(rc)) {
2810 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2815 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2817 /* dump the results */
2820 ads_msgfree(ads, res);
2828 help for net ads search
2830 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2833 "\nnet ads dn <dn> <attributes...>\n"
2834 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2835 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2836 "to show in the results\n\n"
2837 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2838 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2840 net_common_flags_usage(c, argc, argv);
2846 general ADS search function. Useful in diagnosing problems in ADS
2848 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2854 LDAPMessage *res = NULL;
2856 if (argc < 1 || c->display_usage) {
2857 return net_ads_dn_usage(c, argc, argv);
2860 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2867 rc = ads_do_search_all(ads, dn,
2869 "(objectclass=*)", attrs, &res);
2870 if (!ADS_ERR_OK(rc)) {
2871 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2876 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2878 /* dump the results */
2881 ads_msgfree(ads, res);
2888 help for net ads sid search
2890 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2893 "\nnet ads sid <sid> <attributes...>\n"
2894 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2895 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2896 "to show in the results\n\n"
2897 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2899 net_common_flags_usage(c, argc, argv);
2905 general ADS search function. Useful in diagnosing problems in ADS
2907 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2911 const char *sid_string;
2913 LDAPMessage *res = NULL;
2916 if (argc < 1 || c->display_usage) {
2917 return net_ads_sid_usage(c, argc, argv);
2920 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2924 sid_string = argv[0];
2927 if (!string_to_sid(&sid, sid_string)) {
2928 d_fprintf(stderr, _("could not convert sid\n"));
2933 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2934 if (!ADS_ERR_OK(rc)) {
2935 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2940 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2942 /* dump the results */
2945 ads_msgfree(ads, res);
2951 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2956 if (c->display_usage) {
2958 "net ads keytab flush\n"
2961 _("Delete the whole keytab"));
2965 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2968 ret = ads_keytab_flush(ads);
2973 static int net_ads_keytab_add(struct net_context *c,
2982 if (c->display_usage) {
2985 _("net ads keytab add <principal> [principal ...]\n"
2986 " Add principals to local keytab\n"
2987 " principal\tKerberos principal to add to "
2992 d_printf(_("Processing principals to add...\n"));
2993 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2996 for (i = 0; i < argc; i++) {
2997 ret |= ads_keytab_add_entry(ads, argv[i], update_ads);
3003 static int net_ads_keytab_add_default(struct net_context *c,
3007 return net_ads_keytab_add(c, argc, argv, false);
3010 static int net_ads_keytab_add_update_ads(struct net_context *c,
3014 return net_ads_keytab_add(c, argc, argv, true);
3017 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
3022 if (c->display_usage) {
3024 "net ads keytab create\n"
3027 _("Create new default keytab"));
3031 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3034 ret = ads_keytab_create_default(ads);
3039 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
3041 const char *keytab = NULL;
3043 if (c->display_usage) {
3046 _("net ads keytab list [keytab]\n"
3047 " List a local keytab\n"
3048 " keytab\tKeytab to list\n"));
3056 return ads_keytab_list(keytab);
3060 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3062 struct functable func[] = {
3065 net_ads_keytab_add_default,
3067 N_("Add a service principal"),
3068 N_("net ads keytab add\n"
3069 " Add a service principal, updates keytab file only.")
3073 net_ads_keytab_add_update_ads,
3075 N_("Add a service principal"),
3076 N_("net ads keytab add_update_ads\n"
3077 " Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
3081 net_ads_keytab_create,
3083 N_("Create a fresh keytab"),
3084 N_("net ads keytab create\n"
3085 " Create a fresh keytab or update exising one.")
3089 net_ads_keytab_flush,
3091 N_("Remove all keytab entries"),
3092 N_("net ads keytab flush\n"
3093 " Remove all keytab entries")
3097 net_ads_keytab_list,
3099 N_("List a keytab"),
3100 N_("net ads keytab list\n"
3103 {NULL, NULL, 0, NULL, NULL}
3106 if (!USE_KERBEROS_KEYTAB) {
3107 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
3108 "keytab method to use keytab functions.\n"));
3111 return net_run_function(c, argc, argv, "net ads keytab", func);
3114 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
3118 if (c->display_usage) {
3120 "net ads kerberos renew\n"
3123 _("Renew TGT from existing credential cache"));
3127 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
3129 d_printf(_("failed to renew kerberos ticket: %s\n"),
3130 error_message(ret));
3135 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
3136 struct PAC_DATA_CTR **pac_data_ctr)
3140 const char *impersonate_princ_s = NULL;
3141 const char *local_service = NULL;
3144 for (i=0; i<argc; i++) {
3145 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
3146 impersonate_princ_s = get_string_param(argv[i]);
3147 if (impersonate_princ_s == NULL) {
3151 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
3152 local_service = get_string_param(argv[i]);
3153 if (local_service == NULL) {
3159 if (local_service == NULL) {
3160 local_service = talloc_asprintf(c, "%s$@%s",
3161 lp_netbios_name(), lp_realm());
3162 if (local_service == NULL) {
3167 c->opt_password = net_prompt_pass(c, c->opt_user_name);
3169 status = kerberos_return_pac(c,
3178 2592000, /* one month */
3179 impersonate_princ_s,
3182 if (!NT_STATUS_IS_OK(status)) {
3183 d_printf(_("failed to query kerberos PAC: %s\n"),
3193 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
3195 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3198 enum PAC_TYPE type = 0;
3200 if (c->display_usage) {
3202 "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
3205 _("Dump the Kerberos PAC"));
3209 for (i=0; i<argc; i++) {
3210 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
3211 type = get_int_param(argv[i]);
3215 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3224 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
3225 pac_data_ctr->pac_data);
3227 d_printf(_("The Pac: %s\n"), s);
3234 for (i=0; i < pac_data_ctr->pac_data->num_buffers; i++) {
3238 if (pac_data_ctr->pac_data->buffers[i].type != type) {
3242 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
3243 pac_data_ctr->pac_data->buffers[i].info);
3245 d_printf(_("The Pac: %s\n"), s);
3254 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
3256 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3257 char *filename = NULL;
3261 if (c->display_usage) {
3263 "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3266 _("Save the Kerberos PAC"));
3270 for (i=0; i<argc; i++) {
3271 if (strnequal(argv[i], "filename", strlen("filename"))) {
3272 filename = get_string_param(argv[i]);
3273 if (filename == NULL) {
3279 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3284 if (filename == NULL) {
3285 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3289 /* save the raw format */
3290 if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
3291 d_printf(_("failed to save PAC in %s\n"), filename);
3298 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
3300 struct functable func[] = {
3303 net_ads_kerberos_pac_dump,
3305 N_("Dump Kerberos PAC"),
3306 N_("net ads kerberos pac dump\n"
3307 " Dump a Kerberos PAC to stdout")
3311 net_ads_kerberos_pac_save,
3313 N_("Save Kerberos PAC"),
3314 N_("net ads kerberos pac save\n"
3315 " Save a Kerberos PAC in a file")
3318 {NULL, NULL, 0, NULL, NULL}
3321 return net_run_function(c, argc, argv, "net ads kerberos pac", func);
3324 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
3326 TALLOC_CTX *mem_ctx = NULL;
3330 if (c->display_usage) {
3332 "net ads kerberos kinit\n"
3335 _("Get Ticket Granting Ticket (TGT) for the user"));
3339 mem_ctx = talloc_init("net_ads_kerberos_kinit");
3344 c->opt_password = net_prompt_pass(c, c->opt_user_name);
3346 ret = kerberos_kinit_password_ext(c->opt_user_name,
3354 2592000, /* one month */
3357 d_printf(_("failed to kinit password: %s\n"),
3364 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3366 struct functable func[] = {
3369 net_ads_kerberos_kinit,
3371 N_("Retrieve Ticket Granting Ticket (TGT)"),
3372 N_("net ads kerberos kinit\n"
3373 " Receive Ticket Granting Ticket (TGT)")
3377 net_ads_kerberos_renew,
3379 N_("Renew Ticket Granting Ticket from credential cache"),
3380 N_("net ads kerberos renew\n"
3381 " Renew Ticket Granting Ticket (TGT) from "
3386 net_ads_kerberos_pac,
3388 N_("Dump Kerberos PAC"),
3389 N_("net ads kerberos pac\n"
3390 " Dump Kerberos PAC")
3392 {NULL, NULL, 0, NULL, NULL}
3395 return net_run_function(c, argc, argv, "net ads kerberos", func);
3398 static int net_ads_setspn_list(struct net_context *c, int argc, const char **argv)
3402 ADS_STRUCT *ads = NULL;
3403 if (c->display_usage) {
3406 _("net ads setspn list <machinename>\n"));
3410 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3415 ok = ads_setspn_list(ads, argv[0]);
3417 ok = ads_setspn_list(ads, lp_netbios_name());
3429 static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3433 ADS_STRUCT *ads = NULL;
3434 if (c->display_usage || argc < 1) {
3437 _("net ads setspn add <machinename> SPN\n"));
3441 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3446 ok = ads_setspn_add(ads, argv[0], argv[1]);
3448 ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3460 static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3464 ADS_STRUCT *ads = NULL;
3465 if (c->display_usage || argc < 1) {
3468 _("net ads setspn delete <machinename> SPN\n"));
3472 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3477 ok = ads_setspn_delete(ads, argv[0], argv[1]);
3479 ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3491 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3493 struct functable func[] = {
3496 net_ads_setspn_list,
3498 N_("List Service Principal Names (SPN)"),
3499 N_("net ads setspn list machine\n"
3500 " List Service Principal Names (SPN)")
3506 N_("Add Service Principal Names (SPN)"),
3507 N_("net ads setspn add machine spn\n"
3508 " Add Service Principal Names (SPN)")
3512 net_ads_setspn_delete,
3514 N_("Delete Service Principal Names (SPN)"),
3515 N_("net ads setspn delete machine spn\n"
3516 " Delete Service Principal Names (SPN)")
3518 {NULL, NULL, 0, NULL, NULL}
3521 return net_run_function(c, argc, argv, "net ads setspn", func);
3524 static int net_ads_enctype_lookup_account(struct net_context *c,
3526 const char *account,
3528 const char **enctype_str)
3531 const char *attrs[] = {
3532 "msDS-SupportedEncryptionTypes",
3539 filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3541 if (filter == NULL) {
3545 status = ads_search(ads, res, filter, attrs);
3546 if (!ADS_ERR_OK(status)) {
3547 d_printf(_("no account found with filter: %s\n"), filter);
3551 count = ads_count_replies(ads, *res);
3556 d_printf(_("no account found with filter: %s\n"), filter);
3559 d_printf(_("multiple accounts found with filter: %s\n"), filter);
3564 *enctype_str = ads_pull_string(ads, c, *res,
3565 "msDS-SupportedEncryptionTypes");
3566 if (*enctype_str == NULL) {
3567 d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3577 static void net_ads_enctype_dump_enctypes(const char *username,
3578 const char *enctype_str)
3580 int enctypes = atoi(enctype_str);
3582 d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3583 username, enctypes, enctypes);
3585 printf("[%s] 0x%08x DES-CBC-CRC\n",
3586 enctypes & ENC_CRC32 ? "X" : " ",
3588 printf("[%s] 0x%08x DES-CBC-MD5\n",
3589 enctypes & ENC_RSA_MD5 ? "X" : " ",
3591 printf("[%s] 0x%08x RC4-HMAC\n",
3592 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3594 printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3595 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3596 ENC_HMAC_SHA1_96_AES128);
3597 printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3598 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3599 ENC_HMAC_SHA1_96_AES256);
3602 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3606 ADS_STRUCT *ads = NULL;
3607 LDAPMessage *res = NULL;
3608 const char *str = NULL;
3610 if (c->display_usage || (argc < 1)) {
3612 "net ads enctypes list\n"
3615 _("List supported enctypes"));
3619 status = ads_startup(c, false, &ads);
3620 if (!ADS_ERR_OK(status)) {
3621 printf("startup failed\n");
3625 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3630 net_ads_enctype_dump_enctypes(argv[0], str);
3634 ads_msgfree(ads, res);
3640 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3645 LDAPMessage *res = NULL;
3646 const char *etype_list_str;
3649 uint32_t etype_list;
3652 if (c->display_usage || argc < 1) {
3654 "net ads enctypes set <sAMAccountName> [enctypes]\n"
3657 _("Set supported enctypes"));
3661 status = ads_startup(c, false, &ads);
3662 if (!ADS_ERR_OK(status)) {
3663 printf("startup failed\n");
3667 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3672 dn = ads_get_dn(ads, c, res);
3677 etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3678 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3679 etype_list |= ENC_HMAC_SHA1_96_AES128;
3681 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3682 etype_list |= ENC_HMAC_SHA1_96_AES256;
3685 if (argv[1] != NULL) {
3686 sscanf(argv[1], "%i", &etype_list);
3689 etype_list_str = talloc_asprintf(c, "%d", etype_list);
3690 if (!etype_list_str) {
3694 mods = ads_init_mods(c);
3699 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes",
3701 if (!ADS_ERR_OK(status)) {
3705 status = ads_gen_mod(ads, dn, mods);
3706 if (!ADS_ERR_OK(status)) {
3707 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3708 ads_errstr(status));
3712 ads_msgfree(ads, res);
3714 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3719 net_ads_enctype_dump_enctypes(argv[0], str);
3723 ads_msgfree(ads, res);
3729 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3734 LDAPMessage *res = NULL;
3738 if (c->display_usage || argc < 1) {
3740 "net ads enctypes delete <sAMAccountName>\n"
3743 _("Delete supported enctypes"));
3747 status = ads_startup(c, false, &ads);
3748 if (!ADS_ERR_OK(status)) {
3749 printf("startup failed\n");
3753 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3758 dn = ads_get_dn(ads, c, res);
3763 mods = ads_init_mods(c);
3768 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes", NULL);
3769 if (!ADS_ERR_OK(status)) {
3773 status = ads_gen_mod(ads, dn, mods);
3774 if (!ADS_ERR_OK(status)) {
3775 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3776 ads_errstr(status));
3783 ads_msgfree(ads, res);
3788 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3790 struct functable func[] = {
3793 net_ads_enctypes_list,
3795 N_("List the supported encryption types"),
3796 N_("net ads enctypes list\n"
3797 " List the supported encryption types")
3801 net_ads_enctypes_set,
3803 N_("Set the supported encryption types"),
3804 N_("net ads enctypes set\n"
3805 " Set the supported encryption types")
3809 net_ads_enctypes_delete,
3811 N_("Delete the supported encryption types"),
3812 N_("net ads enctypes delete\n"
3813 " Delete the supported encryption types")
3816 {NULL, NULL, 0, NULL, NULL}
3819 return net_run_function(c, argc, argv, "net ads enctypes", func);
3823 int net_ads(struct net_context *c, int argc, const char **argv)
3825 struct functable func[] = {
3830 N_("Display details on remote ADS server"),
3832 " Display details on remote ADS server")
3838 N_("Join the local machine to ADS realm"),
3840 " Join the local machine to ADS realm")
3846 N_("Validate machine account"),
3847 N_("net ads testjoin\n"
3848 " Validate machine account")
3854 N_("Remove the local machine from ADS"),
3855 N_("net ads leave\n"
3856 " Remove the local machine from ADS")
3862 N_("Display machine account details"),
3863 N_("net ads status\n"
3864 " Display machine account details")
3870 N_("List/modify users"),
3872 " List/modify users")
3878 N_("List/modify groups"),
3879 N_("net ads group\n"
3880 " List/modify groups")
3886 N_("Issue dynamic DNS update"),
3888 " Issue dynamic DNS update")
3894 N_("Change user passwords"),
3895 N_("net ads password\n"
3896 " Change user passwords")
3900 net_ads_changetrustpw,
3902 N_("Change trust account password"),
3903 N_("net ads changetrustpw\n"
3904 " Change trust account password")
3910 N_("List/modify printer entries"),
3911 N_("net ads printer\n"
3912 " List/modify printer entries")
3918 N_("Issue LDAP search using filter"),
3919 N_("net ads search\n"
3920 " Issue LDAP search using filter")
3926 N_("Issue LDAP search by DN"),
3928 " Issue LDAP search by DN")
3934 N_("Issue LDAP search by SID"),
3936 " Issue LDAP search by SID")
3942 N_("Display workgroup name"),
3943 N_("net ads workgroup\n"
3944 " Display the workgroup name")
3950 N_("Perform CLDAP query on DC"),
3951 N_("net ads lookup\n"
3952 " Find the ADS DC using CLDAP lookups")
3958 N_("Manage local keytab file"),
3959 N_("net ads keytab\n"
3960 " Manage local keytab file")
3966 N_("Manage Service Principal Names (SPN)s"),
3967 N_("net ads spnset\n"
3968 " Manage Service Principal Names (SPN)s")
3974 N_("Manage group policy objects"),
3976 " Manage group policy objects")
3982 N_("Manage kerberos keytab"),
3983 N_("net ads kerberos\n"
3984 " Manage kerberos keytab")
3990 N_("List/modify supported encryption types"),
3991 N_("net ads enctypes\n"
3992 " List/modify enctypes")
3994 {NULL, NULL, 0, NULL, NULL}
3997 return net_run_function(c, argc, argv, "net ads", func);
4002 static int net_ads_noads(void)
4004 d_fprintf(stderr, _("ADS support not compiled in\n"));
4008 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
4010 return net_ads_noads();
4013 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
4015 return net_ads_noads();
4018 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
4020 return net_ads_noads();
4023 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
4025 return net_ads_noads();
4028 int net_ads_join(struct net_context *c, int argc, const char **argv)
4030 return net_ads_noads();
4033 int net_ads_user(struct net_context *c, int argc, const char **argv)
4035 return net_ads_noads();
4038 int net_ads_group(struct net_context *c, int argc, const char **argv)
4040 return net_ads_noads();
4043 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
4045 return net_ads_noads();
4048 /* this one shouldn't display a message */
4049 int net_ads_check(struct net_context *c)
4054 int net_ads_check_our_domain(struct net_context *c)
4059 int net_ads(struct net_context *c, int argc, const char **argv)
4061 return net_ads_noads();
4064 #endif /* HAVE_ADS */