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"
26 #include "libnet/libnet.h"
30 int net_ads_usage(int argc, const char **argv)
32 d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
33 d_printf(" Join the local machine to a ADS realm\n");
35 d_printf(" Remove the local machine from a ADS realm\n");
36 d_printf("testjoin\n");
37 d_printf(" Validates the machine account in the domain\n");
39 d_printf(" List, add, or delete users in the realm\n");
41 d_printf(" List, add, or delete groups in the realm\n");
43 d_printf(" Displays details regarding a specific AD server\n");
45 d_printf(" Display details regarding the machine's account in AD\n");
47 d_printf(" Performs CLDAP query of AD domain controllers\n");
48 d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
49 d_printf(" Change a user's password using an admin account\n");
50 d_printf(" (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
51 d_printf("changetrustpw\n");
52 d_printf(" Change the trust account password of this machine in the AD tree\n");
53 d_printf("printer [info | publish | remove] <printername> <servername>\n");
54 d_printf(" Lookup, add, or remove directory entry for a printer\n");
55 d_printf("{search,dn,sid}\n");
56 d_printf(" Issue LDAP search queries using a general filter, by DN, or by SID\n");
58 d_printf(" Manage a local keytab file based on the machine account in AD\n");
60 d_printf(" Issue a dynamic DNS update request the server's hostname\n");
61 d_printf(" (using the machine credentials)\n");
66 /* when we do not have sufficient input parameters to contact a remote domain
67 * we always fall back to our own realm - Guenther*/
69 static const char *assume_own_realm(void)
71 if (!opt_host && strequal(lp_workgroup(), opt_target_workgroup)) {
79 do a cldap netlogon query
81 static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
83 char addr[INET6_ADDRSTRLEN];
84 struct cldap_netlogon_reply reply;
87 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
88 if ( !ads_cldap_netlogon(addr, ads->server.realm, &reply ) ) {
89 d_fprintf(stderr, "CLDAP query failed!\n");
93 d_printf("Information for Domain Controller: %s\n\n",
96 d_printf("Response Type: ");
98 case SAMLOGON_AD_UNK_R:
99 d_printf("SAMLOGON\n");
102 d_printf("SAMLOGON_USER\n");
105 d_printf("0x%x\n", reply.type);
109 smb_uuid_unpack(reply.guid, &tmp_guid);
110 d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), tmp_guid));
114 "\tIs a GC of the forest: %s\n"
115 "\tIs an LDAP server: %s\n"
116 "\tSupports DS: %s\n"
117 "\tIs running a KDC: %s\n"
118 "\tIs running time services: %s\n"
119 "\tIs the closest DC: %s\n"
120 "\tIs writable: %s\n"
121 "\tHas a hardware clock: %s\n"
122 "\tIs a non-domain NC serviced by LDAP server: %s\n",
123 (reply.flags & ADS_PDC) ? "yes" : "no",
124 (reply.flags & ADS_GC) ? "yes" : "no",
125 (reply.flags & ADS_LDAP) ? "yes" : "no",
126 (reply.flags & ADS_DS) ? "yes" : "no",
127 (reply.flags & ADS_KDC) ? "yes" : "no",
128 (reply.flags & ADS_TIMESERV) ? "yes" : "no",
129 (reply.flags & ADS_CLOSEST) ? "yes" : "no",
130 (reply.flags & ADS_WRITABLE) ? "yes" : "no",
131 (reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
132 (reply.flags & ADS_NDNC) ? "yes" : "no");
134 printf("Forest:\t\t\t%s\n", reply.forest);
135 printf("Domain:\t\t\t%s\n", reply.domain);
136 printf("Domain Controller:\t%s\n", reply.hostname);
138 printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
139 printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
141 if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
142 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
144 printf("Server Site Name :\t\t%s\n", reply.server_site_name);
145 printf("Client Site Name :\t\t%s\n", reply.client_site_name);
147 d_printf("NT Version: %d\n", reply.version);
148 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
149 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
155 this implements the CLDAP based netlogon lookup requests
156 for finding the domain controller of a ADS domain
158 static int net_ads_lookup(int argc, const char **argv)
162 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
163 d_fprintf(stderr, "Didn't find the cldap server!\n");
167 if (!ads->config.realm) {
168 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
169 ads->ldap.port = 389;
172 return net_ads_cldap_netlogon(ads);
177 static int net_ads_info(int argc, const char **argv)
180 char addr[INET6_ADDRSTRLEN];
182 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
183 d_fprintf(stderr, "Didn't find the ldap server!\n");
187 if (!ads || !ads->config.realm) {
188 d_fprintf(stderr, "Didn't find the ldap server!\n");
192 /* Try to set the server's current time since we didn't do a full
193 TCP LDAP session initially */
195 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
196 d_fprintf( stderr, "Failed to get server's current time!\n");
199 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
201 d_printf("LDAP server: %s\n", addr);
202 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
203 d_printf("Realm: %s\n", ads->config.realm);
204 d_printf("Bind Path: %s\n", ads->config.bind_path);
205 d_printf("LDAP port: %d\n", ads->ldap.port);
206 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
208 d_printf("KDC server: %s\n", ads->auth.kdc_server );
209 d_printf("Server time offset: %d\n", ads->auth.time_offset );
214 static void use_in_memory_ccache(void) {
215 /* Use in-memory credentials cache so we do not interfere with
216 * existing credentials */
217 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
220 static ADS_STATUS ads_startup_int(bool only_own_domain, uint32 auth_flags, ADS_STRUCT **ads_ret)
222 ADS_STRUCT *ads = NULL;
224 bool need_password = False;
225 bool second_time = False;
227 const char *realm = NULL;
228 bool tried_closest_dc = False;
230 /* lp_realm() should be handled by a command line param,
231 However, the join requires that realm be set in smb.conf
232 and compares our realm with the remote server's so this is
233 ok until someone needs more flexibility */
238 if (only_own_domain) {
241 realm = assume_own_realm();
244 ads = ads_init(realm, opt_target_workgroup, opt_host);
246 if (!opt_user_name) {
247 opt_user_name = "administrator";
250 if (opt_user_specified) {
251 need_password = True;
255 if (!opt_password && need_password && !opt_machine_pass) {
256 opt_password = net_prompt_pass(opt_user_name);
259 return ADS_ERROR(LDAP_NO_MEMORY);
264 use_in_memory_ccache();
265 SAFE_FREE(ads->auth.password);
266 ads->auth.password = smb_xstrdup(opt_password);
269 ads->auth.flags |= auth_flags;
270 SAFE_FREE(ads->auth.user_name);
271 ads->auth.user_name = smb_xstrdup(opt_user_name);
274 * If the username is of the form "name@realm",
275 * extract the realm and convert to upper case.
276 * This is only used to establish the connection.
278 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
280 SAFE_FREE(ads->auth.realm);
281 ads->auth.realm = smb_xstrdup(cp);
282 strupper_m(ads->auth.realm);
285 status = ads_connect(ads);
287 if (!ADS_ERR_OK(status)) {
289 if (NT_STATUS_EQUAL(ads_ntstatus(status),
290 NT_STATUS_NO_LOGON_SERVERS)) {
291 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
296 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
297 need_password = True;
306 /* when contacting our own domain, make sure we use the closest DC.
307 * This is done by reconnecting to ADS because only the first call to
308 * ads_connect will give us our own sitename */
310 if ((only_own_domain || !opt_host) && !tried_closest_dc) {
312 tried_closest_dc = True; /* avoid loop */
314 if (!ads->config.tried_closest_dc) {
316 namecache_delete(ads->server.realm, 0x1C);
317 namecache_delete(ads->server.workgroup, 0x1C);
330 ADS_STATUS ads_startup(bool only_own_domain, ADS_STRUCT **ads)
332 return ads_startup_int(only_own_domain, 0, ads);
335 ADS_STATUS ads_startup_nobind(bool only_own_domain, ADS_STRUCT **ads)
337 return ads_startup_int(only_own_domain, ADS_AUTH_NO_BIND, ads);
341 Check to see if connection can be made via ads.
342 ads_startup() stores the password in opt_password if it needs to so
343 that rpc or rap can use it without re-prompting.
345 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
350 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
354 ads->auth.flags |= ADS_AUTH_NO_BIND;
356 status = ads_connect(ads);
357 if ( !ADS_ERR_OK(status) ) {
365 int net_ads_check_our_domain(void)
367 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
370 int net_ads_check(void)
372 return net_ads_check_int(NULL, opt_workgroup, opt_host);
376 determine the netbios workgroup name for a domain
378 static int net_ads_workgroup(int argc, const char **argv)
381 char addr[INET6_ADDRSTRLEN];
382 struct cldap_netlogon_reply reply;
384 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
385 d_fprintf(stderr, "Didn't find the cldap server!\n");
389 if (!ads->config.realm) {
390 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
391 ads->ldap.port = 389;
394 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
395 if ( !ads_cldap_netlogon(addr, ads->server.realm, &reply ) ) {
396 d_fprintf(stderr, "CLDAP query failed!\n");
400 d_printf("Workgroup: %s\n", reply.netbios_domain);
409 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
411 char **disp_fields = (char **) data_area;
413 if (!field) { /* must be end of record */
414 if (disp_fields[0]) {
415 if (!strchr_m(disp_fields[0], '$')) {
417 d_printf("%-21.21s %s\n",
418 disp_fields[0], disp_fields[1]);
420 d_printf("%s\n", disp_fields[0]);
423 SAFE_FREE(disp_fields[0]);
424 SAFE_FREE(disp_fields[1]);
427 if (!values) /* must be new field, indicate string field */
429 if (StrCaseCmp(field, "sAMAccountName") == 0) {
430 disp_fields[0] = SMB_STRDUP((char *) values[0]);
432 if (StrCaseCmp(field, "description") == 0)
433 disp_fields[1] = SMB_STRDUP((char *) values[0]);
437 static int net_ads_user_usage(int argc, const char **argv)
439 return net_help_user(argc, argv);
442 static int ads_user_add(int argc, const char **argv)
447 LDAPMessage *res=NULL;
451 if (argc < 1) return net_ads_user_usage(argc, argv);
453 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
457 status = ads_find_user_acct(ads, &res, argv[0]);
459 if (!ADS_ERR_OK(status)) {
460 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
464 if (ads_count_replies(ads, res)) {
465 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
470 ou_str = SMB_STRDUP(opt_container);
472 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
475 status = ads_add_user_acct(ads, argv[0], ou_str, opt_comment);
477 if (!ADS_ERR_OK(status)) {
478 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
483 /* if no password is to be set, we're done */
485 d_printf("User %s added\n", argv[0]);
490 /* try setting the password */
491 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
492 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
493 ads->auth.time_offset);
495 if (ADS_ERR_OK(status)) {
496 d_printf("User %s added\n", argv[0]);
501 /* password didn't set, delete account */
502 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
503 argv[0], ads_errstr(status));
504 ads_msgfree(ads, res);
505 status=ads_find_user_acct(ads, &res, argv[0]);
506 if (ADS_ERR_OK(status)) {
507 userdn = ads_get_dn(ads, res);
508 ads_del_dn(ads, userdn);
509 ads_memfree(ads, userdn);
514 ads_msgfree(ads, res);
520 static int ads_user_info(int argc, const char **argv)
525 const char *attrs[] = {"memberOf", NULL};
526 char *searchstring=NULL;
531 return net_ads_user_usage(argc, argv);
534 escaped_user = escape_ldap_string_alloc(argv[0]);
537 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
541 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
542 SAFE_FREE(escaped_user);
546 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
547 rc = ads_search(ads, &res, searchstring, attrs);
548 safe_free(searchstring);
550 if (!ADS_ERR_OK(rc)) {
551 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
553 SAFE_FREE(escaped_user);
557 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
558 (LDAPMessage *)res, "memberOf");
563 for (i=0;grouplist[i];i++) {
564 groupname = ldap_explode_dn(grouplist[i], 1);
565 d_printf("%s\n", groupname[0]);
566 ldap_value_free(groupname);
568 ldap_value_free(grouplist);
571 ads_msgfree(ads, res);
573 SAFE_FREE(escaped_user);
577 static int ads_user_delete(int argc, const char **argv)
581 LDAPMessage *res = NULL;
585 return net_ads_user_usage(argc, argv);
588 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
592 rc = ads_find_user_acct(ads, &res, argv[0]);
593 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
594 d_printf("User %s does not exist.\n", argv[0]);
595 ads_msgfree(ads, res);
599 userdn = ads_get_dn(ads, res);
600 ads_msgfree(ads, res);
601 rc = ads_del_dn(ads, userdn);
602 ads_memfree(ads, userdn);
603 if (ADS_ERR_OK(rc)) {
604 d_printf("User %s deleted\n", argv[0]);
608 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
614 int net_ads_user(int argc, const char **argv)
616 struct functable func[] = {
617 {"ADD", ads_user_add},
618 {"INFO", ads_user_info},
619 {"DELETE", ads_user_delete},
624 const char *shortattrs[] = {"sAMAccountName", NULL};
625 const char *longattrs[] = {"sAMAccountName", "description", NULL};
626 char *disp_fields[2] = {NULL, NULL};
629 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
633 if (opt_long_list_entries)
634 d_printf("\nUser name Comment"\
635 "\n-----------------------------\n");
637 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
639 "(objectCategory=user)",
640 opt_long_list_entries ? longattrs :
641 shortattrs, usergrp_display,
644 return ADS_ERR_OK(rc) ? 0 : -1;
647 return net_run_function(argc, argv, func, net_ads_user_usage);
650 static int net_ads_group_usage(int argc, const char **argv)
652 return net_help_group(argc, argv);
655 static int ads_group_add(int argc, const char **argv)
659 LDAPMessage *res=NULL;
664 return net_ads_group_usage(argc, argv);
667 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
671 status = ads_find_user_acct(ads, &res, argv[0]);
673 if (!ADS_ERR_OK(status)) {
674 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
678 if (ads_count_replies(ads, res)) {
679 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
684 ou_str = SMB_STRDUP(opt_container);
686 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
689 status = ads_add_group_acct(ads, argv[0], ou_str, opt_comment);
691 if (ADS_ERR_OK(status)) {
692 d_printf("Group %s added\n", argv[0]);
695 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
701 ads_msgfree(ads, res);
707 static int ads_group_delete(int argc, const char **argv)
711 LDAPMessage *res = NULL;
715 return net_ads_group_usage(argc, argv);
718 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
722 rc = ads_find_user_acct(ads, &res, argv[0]);
723 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
724 d_printf("Group %s does not exist.\n", argv[0]);
725 ads_msgfree(ads, res);
729 groupdn = ads_get_dn(ads, res);
730 ads_msgfree(ads, res);
731 rc = ads_del_dn(ads, groupdn);
732 ads_memfree(ads, groupdn);
733 if (ADS_ERR_OK(rc)) {
734 d_printf("Group %s deleted\n", argv[0]);
738 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
744 int net_ads_group(int argc, const char **argv)
746 struct functable func[] = {
747 {"ADD", ads_group_add},
748 {"DELETE", ads_group_delete},
753 const char *shortattrs[] = {"sAMAccountName", NULL};
754 const char *longattrs[] = {"sAMAccountName", "description", NULL};
755 char *disp_fields[2] = {NULL, NULL};
758 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
762 if (opt_long_list_entries)
763 d_printf("\nGroup name Comment"\
764 "\n-----------------------------\n");
765 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
767 "(objectCategory=group)",
768 opt_long_list_entries ? longattrs :
769 shortattrs, usergrp_display,
773 return ADS_ERR_OK(rc) ? 0 : -1;
775 return net_run_function(argc, argv, func, net_ads_group_usage);
778 static int net_ads_status(int argc, const char **argv)
784 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
788 rc = ads_find_machine_acct(ads, &res, global_myname());
789 if (!ADS_ERR_OK(rc)) {
790 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
795 if (ads_count_replies(ads, res) == 0) {
796 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
806 /*******************************************************************
807 Leave an AD domain. Windows XP disables the machine account.
808 We'll try the same. The old code would do an LDAP delete.
809 That only worked using the machine creds because added the machine
810 with full control to the computer object's ACL.
811 *******************************************************************/
813 static int net_ads_leave(int argc, const char **argv)
816 struct libnet_UnjoinCtx *r = NULL;
820 d_fprintf(stderr, "No realm set, are we joined ?\n");
824 if (!(ctx = talloc_init("net_ads_leave"))) {
825 d_fprintf(stderr, "Could not initialise talloc context.\n");
829 use_in_memory_ccache();
831 werr = libnet_init_UnjoinCtx(ctx, &r);
832 if (!W_ERROR_IS_OK(werr)) {
833 d_fprintf(stderr, "Could not initialise unjoin context.\n");
838 r->in.dc_name = opt_host;
839 r->in.domain_name = lp_realm();
840 r->in.admin_account = opt_user_name;
841 r->in.admin_password = net_prompt_pass(opt_user_name);
842 r->in.modify_config = lp_config_backend_is_registry();
843 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
844 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
846 werr = libnet_Unjoin(ctx, r);
847 if (!W_ERROR_IS_OK(werr)) {
848 d_printf("Failed to leave domain: %s\n",
849 r->out.error_string ? r->out.error_string :
850 get_friendly_werror_msg(werr));
854 if (W_ERROR_IS_OK(werr)) {
855 d_printf("Deleted account for '%s' in realm '%s'\n",
856 r->in.machine_name, r->out.dns_domain_name);
860 /* We couldn't delete it - see if the disable succeeded. */
861 if (r->out.disabled_machine_account) {
862 d_printf("Disabled account for '%s' in realm '%s'\n",
863 r->in.machine_name, r->out.dns_domain_name);
868 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
869 r->in.machine_name, r->out.dns_domain_name);
875 if (W_ERROR_IS_OK(werr)) {
882 static NTSTATUS net_ads_join_ok(void)
884 ADS_STRUCT *ads = NULL;
887 if (!secrets_init()) {
888 DEBUG(1,("Failed to initialise secrets database\n"));
889 return NT_STATUS_ACCESS_DENIED;
892 net_use_krb_machine_account();
894 status = ads_startup(True, &ads);
895 if (!ADS_ERR_OK(status)) {
896 return ads_ntstatus(status);
904 check that an existing join is OK
906 int net_ads_testjoin(int argc, const char **argv)
909 use_in_memory_ccache();
911 /* Display success or failure */
912 status = net_ads_join_ok();
913 if (!NT_STATUS_IS_OK(status)) {
914 fprintf(stderr,"Join to domain is not valid: %s\n",
915 get_friendly_nt_error_msg(status));
919 printf("Join is OK\n");
923 /*******************************************************************
924 Simple configu checks before beginning the join
925 ********************************************************************/
927 static WERROR check_ads_config( void )
929 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
930 d_printf("Host is not configured as a member server.\n");
931 return WERR_INVALID_DOMAIN_ROLE;
934 if (strlen(global_myname()) > 15) {
935 d_printf("Our netbios name can be at most 15 chars long, "
936 "\"%s\" is %u chars long\n", global_myname(),
937 (unsigned int)strlen(global_myname()));
938 return WERR_INVALID_COMPUTER_NAME;
941 if ( lp_security() == SEC_ADS && !*lp_realm()) {
942 d_fprintf(stderr, "realm must be set in in %s for ADS "
943 "join to succeed.\n", get_dyn_CONFIGFILE());
944 return WERR_INVALID_PARAM;
950 /*******************************************************************
951 Send a DNS update request
952 *******************************************************************/
954 #if defined(WITH_DNS_UPDATES)
956 DNS_ERROR DoDNSUpdate(char *pszServerName,
957 const char *pszDomainName, const char *pszHostName,
958 const struct sockaddr_storage *sslist,
961 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
962 const char *machine_name,
963 const struct sockaddr_storage *addrs,
966 struct dns_rr_ns *nameservers = NULL;
968 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
971 const char *dnsdomain = NULL;
972 char *root_domain = NULL;
974 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
975 d_printf("No DNS domain configured for %s. "
976 "Unable to perform DNS Update.\n", machine_name);
977 status = NT_STATUS_INVALID_PARAMETER;
982 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
983 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
984 /* Child domains often do not have NS records. Look
985 for the NS record for the forest root domain
986 (rootDomainNamingContext in therootDSE) */
988 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
989 LDAPMessage *msg = NULL;
991 ADS_STATUS ads_status;
993 if ( !ads->ldap.ld ) {
994 ads_status = ads_connect( ads );
995 if ( !ADS_ERR_OK(ads_status) ) {
996 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1001 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1002 "(objectclass=*)", rootname_attrs, &msg);
1003 if (!ADS_ERR_OK(ads_status)) {
1007 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1009 ads_msgfree( ads, msg );
1013 root_domain = ads_build_domain( root_dn );
1016 ads_msgfree( ads, msg );
1018 /* try again for NS servers */
1020 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1022 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1023 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1024 "realm\n", ads->config.realm));
1028 dnsdomain = root_domain;
1032 /* Now perform the dns update - we'll try non-secure and if we fail,
1033 we'll follow it up with a secure update */
1035 fstrcpy( dns_server, nameservers[0].hostname );
1037 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1038 if (!ERR_DNS_IS_OK(dns_err)) {
1039 status = NT_STATUS_UNSUCCESSFUL;
1044 SAFE_FREE( root_domain );
1049 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1052 struct sockaddr_storage *iplist = NULL;
1053 fstring machine_name;
1056 name_to_fqdn( machine_name, global_myname() );
1057 strlower_m( machine_name );
1059 /* Get our ip address (not the 127.0.0.x address but a real ip
1062 num_addrs = get_my_ip_address( &iplist );
1063 if ( num_addrs <= 0 ) {
1064 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1066 return NT_STATUS_INVALID_PARAMETER;
1069 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1071 SAFE_FREE( iplist );
1077 /*******************************************************************
1078 ********************************************************************/
1080 static int net_ads_join_usage(int argc, const char **argv)
1082 d_printf("net ads join [options]\n");
1083 d_printf("Valid options:\n");
1084 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1085 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1086 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1087 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1088 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1089 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1090 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1091 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1092 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1093 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1094 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1095 d_printf(" the two other attributes.\n");
1100 /*******************************************************************
1101 ********************************************************************/
1103 int net_ads_join(int argc, const char **argv)
1105 TALLOC_CTX *ctx = NULL;
1106 struct libnet_JoinCtx *r = NULL;
1107 const char *domain = lp_realm();
1108 WERROR werr = WERR_SETUP_NOT_JOINED;
1109 bool createupn = False;
1110 const char *machineupn = NULL;
1111 const char *create_in_ou = NULL;
1113 const char *os_name = NULL;
1114 const char *os_version = NULL;
1115 bool modify_config = lp_config_backend_is_registry();
1117 if (!modify_config) {
1119 werr = check_ads_config();
1120 if (!W_ERROR_IS_OK(werr)) {
1121 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1126 if (!(ctx = talloc_init("net_ads_join"))) {
1127 d_fprintf(stderr, "Could not initialise talloc context.\n");
1132 use_in_memory_ccache();
1134 werr = libnet_init_JoinCtx(ctx, &r);
1135 if (!W_ERROR_IS_OK(werr)) {
1139 /* process additional command line args */
1141 for ( i=0; i<argc; i++ ) {
1142 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1144 machineupn = get_string_param(argv[i]);
1146 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1147 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1148 d_fprintf(stderr, "Please supply a valid OU path.\n");
1149 werr = WERR_INVALID_PARAM;
1153 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1154 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1155 d_fprintf(stderr, "Please supply a operating system name.\n");
1156 werr = WERR_INVALID_PARAM;
1160 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1161 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1162 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1163 werr = WERR_INVALID_PARAM;
1173 d_fprintf(stderr, "Please supply a valid domain name\n");
1174 werr = WERR_INVALID_PARAM;
1178 /* Do the domain join here */
1180 r->in.domain_name = domain;
1181 r->in.create_upn = createupn;
1182 r->in.upn = machineupn;
1183 r->in.account_ou = create_in_ou;
1184 r->in.os_name = os_name;
1185 r->in.os_version = os_version;
1186 r->in.dc_name = opt_host;
1187 r->in.admin_account = opt_user_name;
1188 r->in.admin_password = net_prompt_pass(opt_user_name);
1190 r->in.modify_config = modify_config;
1191 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1192 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1193 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1195 werr = libnet_Join(ctx, r);
1196 if (!W_ERROR_IS_OK(werr)) {
1200 /* Check the short name of the domain */
1202 if (!strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1203 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1204 d_printf("domain name obtained from the server.\n");
1205 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1206 d_printf("You should set \"workgroup = %s\" in %s.\n",
1207 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1210 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1212 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1213 r->out.dns_domain_name);
1215 #if defined(WITH_DNS_UPDATES)
1217 /* We enter this block with user creds */
1218 ADS_STRUCT *ads_dns = NULL;
1220 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1221 /* kinit with the machine password */
1223 use_in_memory_ccache();
1224 asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1225 ads_dns->auth.password = secrets_fetch_machine_password(
1226 r->out.netbios_domain_name, NULL, NULL );
1227 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1228 ads_kinit_password( ads_dns );
1231 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1232 d_fprintf( stderr, "DNS update failed!\n" );
1235 /* exit from this block using machine creds */
1236 ads_destroy(&ads_dns);
1245 /* issue an overall failure message at the end. */
1246 d_printf("Failed to join domain: %s\n",
1247 r && r->out.error_string ? r->out.error_string :
1248 get_friendly_werror_msg(werr));
1254 /*******************************************************************
1255 ********************************************************************/
1257 static int net_ads_dns_usage(int argc, const char **argv)
1259 #if defined(WITH_DNS_UPDATES)
1260 d_printf("net ads dns <command>\n");
1261 d_printf("Valid commands:\n");
1262 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1266 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1271 /*******************************************************************
1272 ********************************************************************/
1274 static int net_ads_dns_register(int argc, const char **argv)
1276 #if defined(WITH_DNS_UPDATES)
1282 talloc_enable_leak_report();
1286 d_fprintf(stderr, "net ads dns register\n");
1290 if (!(ctx = talloc_init("net_ads_dns"))) {
1291 d_fprintf(stderr, "Could not initialise talloc context\n");
1295 status = ads_startup(True, &ads);
1296 if ( !ADS_ERR_OK(status) ) {
1297 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1302 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1303 d_fprintf( stderr, "DNS update failed!\n" );
1304 ads_destroy( &ads );
1309 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1316 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1321 #if defined(WITH_DNS_UPDATES)
1322 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1325 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1327 #if defined(WITH_DNS_UPDATES)
1331 talloc_enable_leak_report();
1335 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1340 err = do_gethostbyname(argv[0], argv[1]);
1342 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1347 static int net_ads_dns(int argc, const char *argv[])
1349 struct functable func[] = {
1350 {"REGISTER", net_ads_dns_register},
1351 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1355 return net_run_function(argc, argv, func, net_ads_dns_usage);
1358 /*******************************************************************
1359 ********************************************************************/
1361 int net_ads_printer_usage(int argc, const char **argv)
1364 "\nnet ads printer search <printer>"
1365 "\n\tsearch for a printer in the directory\n"
1366 "\nnet ads printer info <printer> <server>"
1367 "\n\tlookup info in directory for printer on server"
1368 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1369 "\nnet ads printer publish <printername>"
1370 "\n\tpublish printer in directory"
1371 "\n\t(note: printer name is required)\n"
1372 "\nnet ads printer remove <printername>"
1373 "\n\tremove printer from directory"
1374 "\n\t(note: printer name is required)\n");
1378 /*******************************************************************
1379 ********************************************************************/
1381 static int net_ads_printer_search(int argc, const char **argv)
1385 LDAPMessage *res = NULL;
1387 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1391 rc = ads_find_printers(ads, &res);
1393 if (!ADS_ERR_OK(rc)) {
1394 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1395 ads_msgfree(ads, res);
1400 if (ads_count_replies(ads, res) == 0) {
1401 d_fprintf(stderr, "No results found\n");
1402 ads_msgfree(ads, res);
1408 ads_msgfree(ads, res);
1413 static int net_ads_printer_info(int argc, const char **argv)
1417 const char *servername, *printername;
1418 LDAPMessage *res = NULL;
1420 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1425 printername = argv[0];
1431 servername = argv[1];
1433 servername = global_myname();
1436 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1438 if (!ADS_ERR_OK(rc)) {
1439 d_fprintf(stderr, "Server '%s' not found: %s\n",
1440 servername, ads_errstr(rc));
1441 ads_msgfree(ads, res);
1446 if (ads_count_replies(ads, res) == 0) {
1447 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1448 ads_msgfree(ads, res);
1454 ads_msgfree(ads, res);
1460 static int net_ads_printer_publish(int argc, const char **argv)
1464 const char *servername, *printername;
1465 struct cli_state *cli;
1466 struct rpc_pipe_client *pipe_hnd;
1467 struct sockaddr_storage server_ss;
1469 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1470 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1471 char *prt_dn, *srv_dn, **srv_cn;
1472 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1473 LDAPMessage *res = NULL;
1475 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1476 talloc_destroy(mem_ctx);
1481 talloc_destroy(mem_ctx);
1482 return net_ads_printer_usage(argc, argv);
1485 printername = argv[0];
1488 servername = argv[1];
1490 servername = global_myname();
1493 /* Get printer data from SPOOLSS */
1495 resolve_name(servername, &server_ss, 0x20);
1497 nt_status = cli_full_connection(&cli, global_myname(), servername,
1500 opt_user_name, opt_workgroup,
1501 opt_password ? opt_password : "",
1502 CLI_FULL_CONNECTION_USE_KERBEROS,
1505 if (NT_STATUS_IS_ERR(nt_status)) {
1506 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1507 "for %s\n", servername, printername);
1509 talloc_destroy(mem_ctx);
1513 /* Publish on AD server */
1515 ads_find_machine_acct(ads, &res, servername);
1517 if (ads_count_replies(ads, res) == 0) {
1518 d_fprintf(stderr, "Could not find machine account for server %s\n",
1521 talloc_destroy(mem_ctx);
1525 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1526 srv_cn = ldap_explode_dn(srv_dn, 1);
1528 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1529 printername_escaped = escape_rdn_val_string_alloc(printername);
1530 if (!srv_cn_escaped || !printername_escaped) {
1531 SAFE_FREE(srv_cn_escaped);
1532 SAFE_FREE(printername_escaped);
1533 d_fprintf(stderr, "Internal error, out of memory!");
1535 talloc_destroy(mem_ctx);
1539 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1541 SAFE_FREE(srv_cn_escaped);
1542 SAFE_FREE(printername_escaped);
1544 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1546 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1550 talloc_destroy(mem_ctx);
1554 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1558 talloc_destroy(mem_ctx);
1562 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1563 if (!ADS_ERR_OK(rc)) {
1564 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1567 talloc_destroy(mem_ctx);
1571 d_printf("published printer\n");
1574 talloc_destroy(mem_ctx);
1579 static int net_ads_printer_remove(int argc, const char **argv)
1583 const char *servername;
1585 LDAPMessage *res = NULL;
1587 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1592 return net_ads_printer_usage(argc, argv);
1596 servername = argv[1];
1598 servername = global_myname();
1601 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1603 if (!ADS_ERR_OK(rc)) {
1604 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1605 ads_msgfree(ads, res);
1610 if (ads_count_replies(ads, res) == 0) {
1611 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1612 ads_msgfree(ads, res);
1617 prt_dn = ads_get_dn(ads, res);
1618 ads_msgfree(ads, res);
1619 rc = ads_del_dn(ads, prt_dn);
1620 ads_memfree(ads, prt_dn);
1622 if (!ADS_ERR_OK(rc)) {
1623 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1632 static int net_ads_printer(int argc, const char **argv)
1634 struct functable func[] = {
1635 {"SEARCH", net_ads_printer_search},
1636 {"INFO", net_ads_printer_info},
1637 {"PUBLISH", net_ads_printer_publish},
1638 {"REMOVE", net_ads_printer_remove},
1642 return net_run_function(argc, argv, func, net_ads_printer_usage);
1646 static int net_ads_password(int argc, const char **argv)
1649 const char *auth_principal = opt_user_name;
1650 const char *auth_password = opt_password;
1652 char *new_password = NULL;
1657 if (opt_user_name == NULL || opt_password == NULL) {
1658 d_fprintf(stderr, "You must supply an administrator username/password\n");
1663 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1668 if (!strchr_m(user, '@')) {
1669 asprintf(&c, "%s@%s", argv[0], lp_realm());
1673 use_in_memory_ccache();
1674 c = strchr_m(auth_principal, '@');
1681 /* use the realm so we can eventually change passwords for users
1682 in realms other than default */
1683 if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
1687 /* we don't actually need a full connect, but it's the easy way to
1688 fill in the KDC's addresss */
1691 if (!ads->config.realm) {
1692 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1697 new_password = (char *)argv[1];
1699 asprintf(&prompt, "Enter new password for %s:", user);
1700 new_password = getpass(prompt);
1704 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1705 auth_password, user, new_password, ads->auth.time_offset);
1706 if (!ADS_ERR_OK(ret)) {
1707 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1712 d_printf("Password change for %s completed.\n", user);
1718 int net_ads_changetrustpw(int argc, const char **argv)
1721 char *host_principal;
1725 if (!secrets_init()) {
1726 DEBUG(1,("Failed to initialise secrets database\n"));
1730 net_use_krb_machine_account();
1732 use_in_memory_ccache();
1734 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1738 fstrcpy(my_name, global_myname());
1739 strlower_m(my_name);
1740 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1741 d_printf("Changing password for principal: %s\n", host_principal);
1743 ret = ads_change_trust_account_password(ads, host_principal);
1745 if (!ADS_ERR_OK(ret)) {
1746 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1748 SAFE_FREE(host_principal);
1752 d_printf("Password change for principal %s succeeded.\n", host_principal);
1754 if (lp_use_kerberos_keytab()) {
1755 d_printf("Attempting to update system keytab with new password.\n");
1756 if (ads_keytab_create_default(ads)) {
1757 d_printf("Failed to update system keytab.\n");
1762 SAFE_FREE(host_principal);
1768 help for net ads search
1770 static int net_ads_search_usage(int argc, const char **argv)
1773 "\nnet ads search <expression> <attributes...>\n"\
1774 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1775 "The expression is a standard LDAP search expression, and the\n"\
1776 "attributes are a list of LDAP fields to show in the results\n\n"\
1777 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1779 net_common_flags_usage(argc, argv);
1785 general ADS search function. Useful in diagnosing problems in ADS
1787 static int net_ads_search(int argc, const char **argv)
1791 const char *ldap_exp;
1793 LDAPMessage *res = NULL;
1796 return net_ads_search_usage(argc, argv);
1799 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1806 rc = ads_do_search_all(ads, ads->config.bind_path,
1808 ldap_exp, attrs, &res);
1809 if (!ADS_ERR_OK(rc)) {
1810 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1815 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1817 /* dump the results */
1820 ads_msgfree(ads, res);
1828 help for net ads search
1830 static int net_ads_dn_usage(int argc, const char **argv)
1833 "\nnet ads dn <dn> <attributes...>\n"\
1834 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1835 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1836 "to show in the results\n\n"\
1837 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1838 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1840 net_common_flags_usage(argc, argv);
1846 general ADS search function. Useful in diagnosing problems in ADS
1848 static int net_ads_dn(int argc, const char **argv)
1854 LDAPMessage *res = NULL;
1857 return net_ads_dn_usage(argc, argv);
1860 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1867 rc = ads_do_search_all(ads, dn,
1869 "(objectclass=*)", attrs, &res);
1870 if (!ADS_ERR_OK(rc)) {
1871 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1876 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1878 /* dump the results */
1881 ads_msgfree(ads, res);
1888 help for net ads sid search
1890 static int net_ads_sid_usage(int argc, const char **argv)
1893 "\nnet ads sid <sid> <attributes...>\n"\
1894 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1895 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
1896 "to show in the results\n\n"\
1897 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
1899 net_common_flags_usage(argc, argv);
1905 general ADS search function. Useful in diagnosing problems in ADS
1907 static int net_ads_sid(int argc, const char **argv)
1911 const char *sid_string;
1913 LDAPMessage *res = NULL;
1917 return net_ads_sid_usage(argc, argv);
1920 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1924 sid_string = argv[0];
1927 if (!string_to_sid(&sid, sid_string)) {
1928 d_fprintf(stderr, "could not convert sid\n");
1933 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
1934 if (!ADS_ERR_OK(rc)) {
1935 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1940 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1942 /* dump the results */
1945 ads_msgfree(ads, res);
1952 static int net_ads_keytab_usage(int argc, const char **argv)
1955 "net ads keytab <COMMAND>\n"\
1956 "<COMMAND> can be either:\n"\
1957 " ADD Adds new service principal\n"\
1958 " CREATE Creates a fresh keytab\n"\
1959 " FLUSH Flushes out all keytab entries\n"\
1960 " HELP Prints this help message\n"\
1961 " LIST List the keytab\n"\
1962 "The ADD and LIST command will take arguments, the other commands\n"\
1963 "will not take any arguments. The arguments given to ADD\n"\
1964 "should be a list of principals to add. For example, \n"\
1965 " net ads keytab add srv1 srv2\n"\
1966 "will add principals for the services srv1 and srv2 to the\n"\
1967 "system's keytab.\n"\
1968 "The LIST command takes a keytabname.\n"\
1974 static int net_ads_keytab_flush(int argc, const char **argv)
1979 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1982 ret = ads_keytab_flush(ads);
1987 static int net_ads_keytab_add(int argc, const char **argv)
1993 d_printf("Processing principals to add...\n");
1994 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1997 for (i = 0; i < argc; i++) {
1998 ret |= ads_keytab_add_entry(ads, argv[i]);
2004 static int net_ads_keytab_create(int argc, const char **argv)
2009 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2012 ret = ads_keytab_create_default(ads);
2017 static int net_ads_keytab_list(int argc, const char **argv)
2019 const char *keytab = NULL;
2025 return ads_keytab_list(keytab);
2029 int net_ads_keytab(int argc, const char **argv)
2031 struct functable func[] = {
2032 {"ADD", net_ads_keytab_add},
2033 {"CREATE", net_ads_keytab_create},
2034 {"FLUSH", net_ads_keytab_flush},
2035 {"HELP", net_ads_keytab_usage},
2036 {"LIST", net_ads_keytab_list},
2040 if (!lp_use_kerberos_keytab()) {
2041 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2042 use keytab functions.\n");
2045 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2048 static int net_ads_kerberos_usage(int argc, const char **argv)
2051 "net ads kerberos <COMMAND>\n"\
2052 "<COMMAND> can be either:\n"\
2053 " RENEW Renew TGT from existing credential cache\n"\
2054 " PAC Dumps the Kerberos PAC\n"\
2055 " KINIT Retrieve Ticket Granting Ticket (TGT)\n"\
2062 static int net_ads_kerberos_renew(int argc, const char **argv)
2064 int ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2066 d_printf("failed to renew kerberos ticket: %s\n",
2067 error_message(ret));
2072 static int net_ads_kerberos_pac(int argc, const char **argv)
2074 struct PAC_DATA *pac = NULL;
2075 struct PAC_LOGON_INFO *info = NULL;
2076 TALLOC_CTX *mem_ctx = NULL;
2080 mem_ctx = talloc_init("net_ads_kerberos_pac");
2085 opt_password = net_prompt_pass(opt_user_name);
2087 status = kerberos_return_pac(mem_ctx,
2096 2592000, /* one month */
2098 if (!NT_STATUS_IS_OK(status)) {
2099 d_printf("failed to query kerberos PAC: %s\n",
2104 info = get_logon_info_from_pac(pac);
2107 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2108 d_printf("The Pac: %s\n", s);
2113 TALLOC_FREE(mem_ctx);
2117 static int net_ads_kerberos_kinit(int argc, const char **argv)
2119 TALLOC_CTX *mem_ctx = NULL;
2123 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2128 opt_password = net_prompt_pass(opt_user_name);
2130 ret = kerberos_kinit_password_ext(opt_user_name,
2138 2592000, /* one month */
2141 d_printf("failed to kinit password: %s\n",
2148 int net_ads_kerberos(int argc, const char **argv)
2150 struct functable func[] = {
2151 {"KINIT", net_ads_kerberos_kinit},
2152 {"RENEW", net_ads_kerberos_renew},
2153 {"PAC", net_ads_kerberos_pac},
2154 {"HELP", net_ads_kerberos_usage},
2158 return net_run_function(argc, argv, func, net_ads_kerberos_usage);
2162 int net_ads_help(int argc, const char **argv)
2164 struct functable func[] = {
2165 {"USER", net_ads_user_usage},
2166 {"GROUP", net_ads_group_usage},
2167 {"PRINTER", net_ads_printer_usage},
2168 {"SEARCH", net_ads_search_usage},
2169 {"INFO", net_ads_info},
2170 {"JOIN", net_ads_join_usage},
2171 {"DNS", net_ads_dns_usage},
2172 {"LEAVE", net_ads_leave},
2173 {"STATUS", net_ads_status},
2174 {"PASSWORD", net_ads_password},
2175 {"CHANGETRUSTPW", net_ads_changetrustpw},
2179 return net_run_function(argc, argv, func, net_ads_usage);
2182 int net_ads(int argc, const char **argv)
2184 struct functable func[] = {
2185 {"INFO", net_ads_info},
2186 {"JOIN", net_ads_join},
2187 {"TESTJOIN", net_ads_testjoin},
2188 {"LEAVE", net_ads_leave},
2189 {"STATUS", net_ads_status},
2190 {"USER", net_ads_user},
2191 {"GROUP", net_ads_group},
2192 {"DNS", net_ads_dns},
2193 {"PASSWORD", net_ads_password},
2194 {"CHANGETRUSTPW", net_ads_changetrustpw},
2195 {"PRINTER", net_ads_printer},
2196 {"SEARCH", net_ads_search},
2198 {"SID", net_ads_sid},
2199 {"WORKGROUP", net_ads_workgroup},
2200 {"LOOKUP", net_ads_lookup},
2201 {"KEYTAB", net_ads_keytab},
2202 {"GPO", net_ads_gpo},
2203 {"KERBEROS", net_ads_kerberos},
2204 {"HELP", net_ads_help},
2208 return net_run_function(argc, argv, func, net_ads_usage);
2213 static int net_ads_noads(void)
2215 d_fprintf(stderr, "ADS support not compiled in\n");
2219 int net_ads_keytab(int argc, const char **argv)
2221 return net_ads_noads();
2224 int net_ads_kerberos(int argc, const char **argv)
2226 return net_ads_noads();
2229 int net_ads_usage(int argc, const char **argv)
2231 return net_ads_noads();
2234 int net_ads_help(int argc, const char **argv)
2236 return net_ads_noads();
2239 int net_ads_changetrustpw(int argc, const char **argv)
2241 return net_ads_noads();
2244 int net_ads_join(int argc, const char **argv)
2246 return net_ads_noads();
2249 int net_ads_user(int argc, const char **argv)
2251 return net_ads_noads();
2254 int net_ads_group(int argc, const char **argv)
2256 return net_ads_noads();
2259 /* this one shouldn't display a message */
2260 int net_ads_check(void)
2265 int net_ads_check_our_domain(void)
2270 int net_ads(int argc, const char **argv)
2272 return net_ads_usage(argc, argv);
2275 #endif /* WITH_ADS */