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;
819 if (!(ctx = talloc_init("net_ads_leave"))) {
820 d_fprintf(stderr, "Could not initialise talloc context.\n");
824 use_in_memory_ccache();
826 werr = libnet_init_UnjoinCtx(ctx, &r);
827 if (!W_ERROR_IS_OK(werr)) {
828 d_fprintf(stderr, "Could not initialise unjoin context.\n");
833 r->in.dc_name = opt_host;
834 r->in.domain_name = lp_realm();
835 r->in.admin_account = opt_user_name;
836 r->in.admin_password = net_prompt_pass(opt_user_name);
837 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
838 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
840 werr = libnet_Unjoin(ctx, r);
841 if (!W_ERROR_IS_OK(werr)) {
842 d_printf("Failed to leave domain: %s\n",
843 r->out.error_string ? r->out.error_string :
844 get_friendly_werror_msg(werr));
848 if (W_ERROR_IS_OK(werr)) {
849 d_printf("Deleted account for '%s' in realm '%s'\n",
850 r->in.machine_name, r->out.dns_domain_name);
854 /* We couldn't delete it - see if the disable succeeded. */
855 if (r->out.disabled_machine_account) {
856 d_printf("Disabled account for '%s' in realm '%s'\n",
857 r->in.machine_name, r->out.dns_domain_name);
862 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
863 r->in.machine_name, r->out.dns_domain_name);
869 if (W_ERROR_IS_OK(werr)) {
876 static NTSTATUS net_ads_join_ok(void)
878 ADS_STRUCT *ads = NULL;
881 if (!secrets_init()) {
882 DEBUG(1,("Failed to initialise secrets database\n"));
883 return NT_STATUS_ACCESS_DENIED;
886 net_use_krb_machine_account();
888 status = ads_startup(True, &ads);
889 if (!ADS_ERR_OK(status)) {
890 return ads_ntstatus(status);
898 check that an existing join is OK
900 int net_ads_testjoin(int argc, const char **argv)
903 use_in_memory_ccache();
905 /* Display success or failure */
906 status = net_ads_join_ok();
907 if (!NT_STATUS_IS_OK(status)) {
908 fprintf(stderr,"Join to domain is not valid: %s\n",
909 get_friendly_nt_error_msg(status));
913 printf("Join is OK\n");
917 /*******************************************************************
918 Simple configu checks before beginning the join
919 ********************************************************************/
921 static WERROR check_ads_config( void )
923 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
924 d_printf("Host is not configured as a member server.\n");
925 return WERR_INVALID_DOMAIN_ROLE;
928 if (strlen(global_myname()) > 15) {
929 d_printf("Our netbios name can be at most 15 chars long, "
930 "\"%s\" is %u chars long\n", global_myname(),
931 (unsigned int)strlen(global_myname()));
932 return WERR_INVALID_COMPUTER_NAME;
935 if ( lp_security() == SEC_ADS && !*lp_realm()) {
936 d_fprintf(stderr, "realm must be set in in %s for ADS "
937 "join to succeed.\n", get_dyn_CONFIGFILE());
938 return WERR_INVALID_PARAM;
944 /*******************************************************************
945 Send a DNS update request
946 *******************************************************************/
948 #if defined(WITH_DNS_UPDATES)
950 DNS_ERROR DoDNSUpdate(char *pszServerName,
951 const char *pszDomainName, const char *pszHostName,
952 const struct sockaddr_storage *sslist,
955 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
956 const char *machine_name,
957 const struct sockaddr_storage *addrs,
960 struct dns_rr_ns *nameservers = NULL;
962 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
965 const char *dnsdomain = NULL;
966 char *root_domain = NULL;
968 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
969 d_printf("No DNS domain configured for %s. "
970 "Unable to perform DNS Update.\n", machine_name);
971 status = NT_STATUS_INVALID_PARAMETER;
976 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
977 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
978 /* Child domains often do not have NS records. Look
979 for the NS record for the forest root domain
980 (rootDomainNamingContext in therootDSE) */
982 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
983 LDAPMessage *msg = NULL;
985 ADS_STATUS ads_status;
987 if ( !ads->ldap.ld ) {
988 ads_status = ads_connect( ads );
989 if ( !ADS_ERR_OK(ads_status) ) {
990 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
995 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
996 "(objectclass=*)", rootname_attrs, &msg);
997 if (!ADS_ERR_OK(ads_status)) {
1001 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1003 ads_msgfree( ads, msg );
1007 root_domain = ads_build_domain( root_dn );
1010 ads_msgfree( ads, msg );
1012 /* try again for NS servers */
1014 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1016 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1017 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1018 "realm\n", ads->config.realm));
1022 dnsdomain = root_domain;
1026 /* Now perform the dns update - we'll try non-secure and if we fail,
1027 we'll follow it up with a secure update */
1029 fstrcpy( dns_server, nameservers[0].hostname );
1031 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1032 if (!ERR_DNS_IS_OK(dns_err)) {
1033 status = NT_STATUS_UNSUCCESSFUL;
1038 SAFE_FREE( root_domain );
1043 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1046 struct sockaddr_storage *iplist = NULL;
1047 fstring machine_name;
1050 name_to_fqdn( machine_name, global_myname() );
1051 strlower_m( machine_name );
1053 /* Get our ip address (not the 127.0.0.x address but a real ip
1056 num_addrs = get_my_ip_address( &iplist );
1057 if ( num_addrs <= 0 ) {
1058 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1060 return NT_STATUS_INVALID_PARAMETER;
1063 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1065 SAFE_FREE( iplist );
1071 /*******************************************************************
1072 ********************************************************************/
1074 static int net_ads_join_usage(int argc, const char **argv)
1076 d_printf("net ads join [options]\n");
1077 d_printf("Valid options:\n");
1078 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1079 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1080 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1081 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1082 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1083 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1084 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1085 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1086 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1087 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1088 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1089 d_printf(" the two other attributes.\n");
1094 /*******************************************************************
1095 ********************************************************************/
1097 int net_ads_join(int argc, const char **argv)
1099 TALLOC_CTX *ctx = NULL;
1100 struct libnet_JoinCtx *r = NULL;
1101 const char *domain = lp_realm();
1102 WERROR werr = WERR_SETUP_NOT_JOINED;
1103 bool createupn = False;
1104 const char *machineupn = NULL;
1105 const char *create_in_ou = NULL;
1107 const char *os_name = NULL;
1108 const char *os_version = NULL;
1110 werr = check_ads_config();
1111 if (!W_ERROR_IS_OK(werr)) {
1112 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1116 if (!(ctx = talloc_init("net_ads_join"))) {
1117 d_fprintf(stderr, "Could not initialise talloc context.\n");
1122 use_in_memory_ccache();
1124 werr = libnet_init_JoinCtx(ctx, &r);
1125 if (!W_ERROR_IS_OK(werr)) {
1129 /* process additional command line args */
1131 for ( i=0; i<argc; i++ ) {
1132 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1134 machineupn = get_string_param(argv[i]);
1136 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1137 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1138 d_fprintf(stderr, "Please supply a valid OU path.\n");
1139 werr = WERR_INVALID_PARAM;
1143 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1144 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1145 d_fprintf(stderr, "Please supply a operating system name.\n");
1146 werr = WERR_INVALID_PARAM;
1150 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1151 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1152 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1153 werr = WERR_INVALID_PARAM;
1162 /* Do the domain join here */
1164 r->in.domain_name = domain;
1165 r->in.create_upn = createupn;
1166 r->in.upn = machineupn;
1167 r->in.account_ou = create_in_ou;
1168 r->in.os_name = os_name;
1169 r->in.os_version = os_version;
1170 r->in.dc_name = opt_host;
1171 r->in.admin_account = opt_user_name;
1172 r->in.admin_password = net_prompt_pass(opt_user_name);
1174 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1175 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1176 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1178 werr = libnet_Join(ctx, r);
1179 if (!W_ERROR_IS_OK(werr)) {
1183 /* Check the short name of the domain */
1185 if (!strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1186 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1187 d_printf("domain name obtained from the server.\n");
1188 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1189 d_printf("You should set \"workgroup = %s\" in %s.\n",
1190 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1193 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1195 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1196 r->out.dns_domain_name);
1198 #if defined(WITH_DNS_UPDATES)
1200 /* We enter this block with user creds */
1201 ADS_STRUCT *ads_dns = NULL;
1203 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1204 /* kinit with the machine password */
1206 use_in_memory_ccache();
1207 asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1208 ads_dns->auth.password = secrets_fetch_machine_password(
1209 lp_workgroup(), NULL, NULL );
1210 ads_dns->auth.realm = SMB_STRDUP( lp_realm() );
1211 ads_kinit_password( ads_dns );
1214 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1215 d_fprintf( stderr, "DNS update failed!\n" );
1218 /* exit from this block using machine creds */
1219 ads_destroy(&ads_dns);
1228 /* issue an overall failure message at the end. */
1229 d_printf("Failed to join domain: %s\n",
1230 r && r->out.error_string ? r->out.error_string :
1231 get_friendly_werror_msg(werr));
1237 /*******************************************************************
1238 ********************************************************************/
1240 static int net_ads_dns_usage(int argc, const char **argv)
1242 #if defined(WITH_DNS_UPDATES)
1243 d_printf("net ads dns <command>\n");
1244 d_printf("Valid commands:\n");
1245 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1249 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1254 /*******************************************************************
1255 ********************************************************************/
1257 static int net_ads_dns_register(int argc, const char **argv)
1259 #if defined(WITH_DNS_UPDATES)
1265 talloc_enable_leak_report();
1269 d_fprintf(stderr, "net ads dns register\n");
1273 if (!(ctx = talloc_init("net_ads_dns"))) {
1274 d_fprintf(stderr, "Could not initialise talloc context\n");
1278 status = ads_startup(True, &ads);
1279 if ( !ADS_ERR_OK(status) ) {
1280 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1285 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1286 d_fprintf( stderr, "DNS update failed!\n" );
1287 ads_destroy( &ads );
1292 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1299 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1304 #if defined(WITH_DNS_UPDATES)
1305 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1308 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1310 #if defined(WITH_DNS_UPDATES)
1314 talloc_enable_leak_report();
1318 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1323 err = do_gethostbyname(argv[0], argv[1]);
1325 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1330 static int net_ads_dns(int argc, const char *argv[])
1332 struct functable func[] = {
1333 {"REGISTER", net_ads_dns_register},
1334 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1338 return net_run_function(argc, argv, func, net_ads_dns_usage);
1341 /*******************************************************************
1342 ********************************************************************/
1344 int net_ads_printer_usage(int argc, const char **argv)
1347 "\nnet ads printer search <printer>"
1348 "\n\tsearch for a printer in the directory\n"
1349 "\nnet ads printer info <printer> <server>"
1350 "\n\tlookup info in directory for printer on server"
1351 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1352 "\nnet ads printer publish <printername>"
1353 "\n\tpublish printer in directory"
1354 "\n\t(note: printer name is required)\n"
1355 "\nnet ads printer remove <printername>"
1356 "\n\tremove printer from directory"
1357 "\n\t(note: printer name is required)\n");
1361 /*******************************************************************
1362 ********************************************************************/
1364 static int net_ads_printer_search(int argc, const char **argv)
1368 LDAPMessage *res = NULL;
1370 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1374 rc = ads_find_printers(ads, &res);
1376 if (!ADS_ERR_OK(rc)) {
1377 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1378 ads_msgfree(ads, res);
1383 if (ads_count_replies(ads, res) == 0) {
1384 d_fprintf(stderr, "No results found\n");
1385 ads_msgfree(ads, res);
1391 ads_msgfree(ads, res);
1396 static int net_ads_printer_info(int argc, const char **argv)
1400 const char *servername, *printername;
1401 LDAPMessage *res = NULL;
1403 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1408 printername = argv[0];
1414 servername = argv[1];
1416 servername = global_myname();
1419 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1421 if (!ADS_ERR_OK(rc)) {
1422 d_fprintf(stderr, "Server '%s' not found: %s\n",
1423 servername, ads_errstr(rc));
1424 ads_msgfree(ads, res);
1429 if (ads_count_replies(ads, res) == 0) {
1430 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1431 ads_msgfree(ads, res);
1437 ads_msgfree(ads, res);
1443 static int net_ads_printer_publish(int argc, const char **argv)
1447 const char *servername, *printername;
1448 struct cli_state *cli;
1449 struct rpc_pipe_client *pipe_hnd;
1450 struct sockaddr_storage server_ss;
1452 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1453 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1454 char *prt_dn, *srv_dn, **srv_cn;
1455 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1456 LDAPMessage *res = NULL;
1458 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1459 talloc_destroy(mem_ctx);
1464 talloc_destroy(mem_ctx);
1465 return net_ads_printer_usage(argc, argv);
1468 printername = argv[0];
1471 servername = argv[1];
1473 servername = global_myname();
1476 /* Get printer data from SPOOLSS */
1478 resolve_name(servername, &server_ss, 0x20);
1480 nt_status = cli_full_connection(&cli, global_myname(), servername,
1483 opt_user_name, opt_workgroup,
1484 opt_password ? opt_password : "",
1485 CLI_FULL_CONNECTION_USE_KERBEROS,
1488 if (NT_STATUS_IS_ERR(nt_status)) {
1489 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1490 "for %s\n", servername, printername);
1492 talloc_destroy(mem_ctx);
1496 /* Publish on AD server */
1498 ads_find_machine_acct(ads, &res, servername);
1500 if (ads_count_replies(ads, res) == 0) {
1501 d_fprintf(stderr, "Could not find machine account for server %s\n",
1504 talloc_destroy(mem_ctx);
1508 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1509 srv_cn = ldap_explode_dn(srv_dn, 1);
1511 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1512 printername_escaped = escape_rdn_val_string_alloc(printername);
1513 if (!srv_cn_escaped || !printername_escaped) {
1514 SAFE_FREE(srv_cn_escaped);
1515 SAFE_FREE(printername_escaped);
1516 d_fprintf(stderr, "Internal error, out of memory!");
1518 talloc_destroy(mem_ctx);
1522 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1524 SAFE_FREE(srv_cn_escaped);
1525 SAFE_FREE(printername_escaped);
1527 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1529 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1533 talloc_destroy(mem_ctx);
1537 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1541 talloc_destroy(mem_ctx);
1545 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1546 if (!ADS_ERR_OK(rc)) {
1547 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1550 talloc_destroy(mem_ctx);
1554 d_printf("published printer\n");
1557 talloc_destroy(mem_ctx);
1562 static int net_ads_printer_remove(int argc, const char **argv)
1566 const char *servername;
1568 LDAPMessage *res = NULL;
1570 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1575 return net_ads_printer_usage(argc, argv);
1579 servername = argv[1];
1581 servername = global_myname();
1584 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1586 if (!ADS_ERR_OK(rc)) {
1587 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1588 ads_msgfree(ads, res);
1593 if (ads_count_replies(ads, res) == 0) {
1594 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1595 ads_msgfree(ads, res);
1600 prt_dn = ads_get_dn(ads, res);
1601 ads_msgfree(ads, res);
1602 rc = ads_del_dn(ads, prt_dn);
1603 ads_memfree(ads, prt_dn);
1605 if (!ADS_ERR_OK(rc)) {
1606 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1615 static int net_ads_printer(int argc, const char **argv)
1617 struct functable func[] = {
1618 {"SEARCH", net_ads_printer_search},
1619 {"INFO", net_ads_printer_info},
1620 {"PUBLISH", net_ads_printer_publish},
1621 {"REMOVE", net_ads_printer_remove},
1625 return net_run_function(argc, argv, func, net_ads_printer_usage);
1629 static int net_ads_password(int argc, const char **argv)
1632 const char *auth_principal = opt_user_name;
1633 const char *auth_password = opt_password;
1635 char *new_password = NULL;
1640 if (opt_user_name == NULL || opt_password == NULL) {
1641 d_fprintf(stderr, "You must supply an administrator username/password\n");
1646 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1651 if (!strchr_m(user, '@')) {
1652 asprintf(&c, "%s@%s", argv[0], lp_realm());
1656 use_in_memory_ccache();
1657 c = strchr_m(auth_principal, '@');
1664 /* use the realm so we can eventually change passwords for users
1665 in realms other than default */
1666 if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
1670 /* we don't actually need a full connect, but it's the easy way to
1671 fill in the KDC's addresss */
1674 if (!ads->config.realm) {
1675 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1680 new_password = (char *)argv[1];
1682 asprintf(&prompt, "Enter new password for %s:", user);
1683 new_password = getpass(prompt);
1687 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1688 auth_password, user, new_password, ads->auth.time_offset);
1689 if (!ADS_ERR_OK(ret)) {
1690 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1695 d_printf("Password change for %s completed.\n", user);
1701 int net_ads_changetrustpw(int argc, const char **argv)
1704 char *host_principal;
1708 if (!secrets_init()) {
1709 DEBUG(1,("Failed to initialise secrets database\n"));
1713 net_use_krb_machine_account();
1715 use_in_memory_ccache();
1717 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1721 fstrcpy(my_name, global_myname());
1722 strlower_m(my_name);
1723 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1724 d_printf("Changing password for principal: %s\n", host_principal);
1726 ret = ads_change_trust_account_password(ads, host_principal);
1728 if (!ADS_ERR_OK(ret)) {
1729 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1731 SAFE_FREE(host_principal);
1735 d_printf("Password change for principal %s succeeded.\n", host_principal);
1737 if (lp_use_kerberos_keytab()) {
1738 d_printf("Attempting to update system keytab with new password.\n");
1739 if (ads_keytab_create_default(ads)) {
1740 d_printf("Failed to update system keytab.\n");
1745 SAFE_FREE(host_principal);
1751 help for net ads search
1753 static int net_ads_search_usage(int argc, const char **argv)
1756 "\nnet ads search <expression> <attributes...>\n"\
1757 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1758 "The expression is a standard LDAP search expression, and the\n"\
1759 "attributes are a list of LDAP fields to show in the results\n\n"\
1760 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1762 net_common_flags_usage(argc, argv);
1768 general ADS search function. Useful in diagnosing problems in ADS
1770 static int net_ads_search(int argc, const char **argv)
1774 const char *ldap_exp;
1776 LDAPMessage *res = NULL;
1779 return net_ads_search_usage(argc, argv);
1782 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1789 rc = ads_do_search_all(ads, ads->config.bind_path,
1791 ldap_exp, attrs, &res);
1792 if (!ADS_ERR_OK(rc)) {
1793 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1798 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1800 /* dump the results */
1803 ads_msgfree(ads, res);
1811 help for net ads search
1813 static int net_ads_dn_usage(int argc, const char **argv)
1816 "\nnet ads dn <dn> <attributes...>\n"\
1817 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1818 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1819 "to show in the results\n\n"\
1820 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1821 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1823 net_common_flags_usage(argc, argv);
1829 general ADS search function. Useful in diagnosing problems in ADS
1831 static int net_ads_dn(int argc, const char **argv)
1837 LDAPMessage *res = NULL;
1840 return net_ads_dn_usage(argc, argv);
1843 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1850 rc = ads_do_search_all(ads, dn,
1852 "(objectclass=*)", attrs, &res);
1853 if (!ADS_ERR_OK(rc)) {
1854 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1859 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1861 /* dump the results */
1864 ads_msgfree(ads, res);
1871 help for net ads sid search
1873 static int net_ads_sid_usage(int argc, const char **argv)
1876 "\nnet ads sid <sid> <attributes...>\n"\
1877 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1878 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
1879 "to show in the results\n\n"\
1880 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
1882 net_common_flags_usage(argc, argv);
1888 general ADS search function. Useful in diagnosing problems in ADS
1890 static int net_ads_sid(int argc, const char **argv)
1894 const char *sid_string;
1896 LDAPMessage *res = NULL;
1900 return net_ads_sid_usage(argc, argv);
1903 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1907 sid_string = argv[0];
1910 if (!string_to_sid(&sid, sid_string)) {
1911 d_fprintf(stderr, "could not convert sid\n");
1916 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
1917 if (!ADS_ERR_OK(rc)) {
1918 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1923 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1925 /* dump the results */
1928 ads_msgfree(ads, res);
1935 static int net_ads_keytab_usage(int argc, const char **argv)
1938 "net ads keytab <COMMAND>\n"\
1939 "<COMMAND> can be either:\n"\
1940 " ADD Adds new service principal\n"\
1941 " CREATE Creates a fresh keytab\n"\
1942 " FLUSH Flushes out all keytab entries\n"\
1943 " HELP Prints this help message\n"\
1944 " LIST List the keytab\n"\
1945 "The ADD and LIST command will take arguments, the other commands\n"\
1946 "will not take any arguments. The arguments given to ADD\n"\
1947 "should be a list of principals to add. For example, \n"\
1948 " net ads keytab add srv1 srv2\n"\
1949 "will add principals for the services srv1 and srv2 to the\n"\
1950 "system's keytab.\n"\
1951 "The LIST command takes a keytabname.\n"\
1957 static int net_ads_keytab_flush(int argc, const char **argv)
1962 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1965 ret = ads_keytab_flush(ads);
1970 static int net_ads_keytab_add(int argc, const char **argv)
1976 d_printf("Processing principals to add...\n");
1977 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1980 for (i = 0; i < argc; i++) {
1981 ret |= ads_keytab_add_entry(ads, argv[i]);
1987 static int net_ads_keytab_create(int argc, const char **argv)
1992 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1995 ret = ads_keytab_create_default(ads);
2000 static int net_ads_keytab_list(int argc, const char **argv)
2002 const char *keytab = NULL;
2008 return ads_keytab_list(keytab);
2012 int net_ads_keytab(int argc, const char **argv)
2014 struct functable func[] = {
2015 {"ADD", net_ads_keytab_add},
2016 {"CREATE", net_ads_keytab_create},
2017 {"FLUSH", net_ads_keytab_flush},
2018 {"HELP", net_ads_keytab_usage},
2019 {"LIST", net_ads_keytab_list},
2023 if (!lp_use_kerberos_keytab()) {
2024 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2025 use keytab functions.\n");
2028 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2031 static int net_ads_kerberos_usage(int argc, const char **argv)
2034 "net ads kerberos <COMMAND>\n"\
2035 "<COMMAND> can be either:\n"\
2036 " RENEW Renew TGT from existing credential cache\n"\
2037 " PAC Dumps the Kerberos PAC\n"\
2038 " KINIT Retrieve Ticket Granting Ticket (TGT)\n"\
2045 static int net_ads_kerberos_renew(int argc, const char **argv)
2047 int ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2049 d_printf("failed to renew kerberos ticket: %s\n",
2050 error_message(ret));
2055 static int net_ads_kerberos_pac(int argc, const char **argv)
2057 struct PAC_DATA *pac = NULL;
2058 struct PAC_LOGON_INFO *info = NULL;
2059 TALLOC_CTX *mem_ctx = NULL;
2063 mem_ctx = talloc_init("net_ads_kerberos_pac");
2068 opt_password = net_prompt_pass(opt_user_name);
2070 status = kerberos_return_pac(mem_ctx,
2079 2592000, /* one month */
2081 if (!NT_STATUS_IS_OK(status)) {
2082 d_printf("failed to query kerberos PAC: %s\n",
2087 info = get_logon_info_from_pac(pac);
2090 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2091 d_printf("The Pac: %s\n", s);
2096 TALLOC_FREE(mem_ctx);
2100 static int net_ads_kerberos_kinit(int argc, const char **argv)
2102 TALLOC_CTX *mem_ctx = NULL;
2106 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2111 opt_password = net_prompt_pass(opt_user_name);
2113 ret = kerberos_kinit_password_ext(opt_user_name,
2121 2592000, /* one month */
2124 d_printf("failed to kinit password: %s\n",
2131 int net_ads_kerberos(int argc, const char **argv)
2133 struct functable func[] = {
2134 {"KINIT", net_ads_kerberos_kinit},
2135 {"RENEW", net_ads_kerberos_renew},
2136 {"PAC", net_ads_kerberos_pac},
2137 {"HELP", net_ads_kerberos_usage},
2141 return net_run_function(argc, argv, func, net_ads_kerberos_usage);
2145 int net_ads_help(int argc, const char **argv)
2147 struct functable func[] = {
2148 {"USER", net_ads_user_usage},
2149 {"GROUP", net_ads_group_usage},
2150 {"PRINTER", net_ads_printer_usage},
2151 {"SEARCH", net_ads_search_usage},
2152 {"INFO", net_ads_info},
2153 {"JOIN", net_ads_join_usage},
2154 {"DNS", net_ads_dns_usage},
2155 {"LEAVE", net_ads_leave},
2156 {"STATUS", net_ads_status},
2157 {"PASSWORD", net_ads_password},
2158 {"CHANGETRUSTPW", net_ads_changetrustpw},
2162 return net_run_function(argc, argv, func, net_ads_usage);
2165 int net_ads(int argc, const char **argv)
2167 struct functable func[] = {
2168 {"INFO", net_ads_info},
2169 {"JOIN", net_ads_join},
2170 {"TESTJOIN", net_ads_testjoin},
2171 {"LEAVE", net_ads_leave},
2172 {"STATUS", net_ads_status},
2173 {"USER", net_ads_user},
2174 {"GROUP", net_ads_group},
2175 {"DNS", net_ads_dns},
2176 {"PASSWORD", net_ads_password},
2177 {"CHANGETRUSTPW", net_ads_changetrustpw},
2178 {"PRINTER", net_ads_printer},
2179 {"SEARCH", net_ads_search},
2181 {"SID", net_ads_sid},
2182 {"WORKGROUP", net_ads_workgroup},
2183 {"LOOKUP", net_ads_lookup},
2184 {"KEYTAB", net_ads_keytab},
2185 {"GPO", net_ads_gpo},
2186 {"KERBEROS", net_ads_kerberos},
2187 {"HELP", net_ads_help},
2191 return net_run_function(argc, argv, func, net_ads_usage);
2196 static int net_ads_noads(void)
2198 d_fprintf(stderr, "ADS support not compiled in\n");
2202 int net_ads_keytab(int argc, const char **argv)
2204 return net_ads_noads();
2207 int net_ads_kerberos(int argc, const char **argv)
2209 return net_ads_noads();
2212 int net_ads_usage(int argc, const char **argv)
2214 return net_ads_noads();
2217 int net_ads_help(int argc, const char **argv)
2219 return net_ads_noads();
2222 int net_ads_changetrustpw(int argc, const char **argv)
2224 return net_ads_noads();
2227 int net_ads_join(int argc, const char **argv)
2229 return net_ads_noads();
2232 int net_ads_user(int argc, const char **argv)
2234 return net_ads_noads();
2237 int net_ads_group(int argc, const char **argv)
2239 return net_ads_noads();
2242 /* this one shouldn't display a message */
2243 int net_ads_check(void)
2248 int net_ads_check_our_domain(void)
2253 int net_ads(int argc, const char **argv)
2255 return net_ads_usage(argc, argv);
2258 #endif /* WITH_ADS */