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");
832 r->in.debug = opt_verbose;
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 NTSTATUS 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 NT_STATUS_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 NT_STATUS_NAME_TOO_LONG;
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 NT_STATUS_INVALID_PARAMETER;
941 if (!secrets_init()) {
942 DEBUG(1,("Failed to initialise secrets database\n"));
943 /* This is a good bet for failure of secrets_init ... */
944 return NT_STATUS_ACCESS_DENIED;
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)
1106 TALLOC_CTX *ctx = NULL;
1107 struct libnet_JoinCtx *r = NULL;
1108 const char *domain = lp_realm();
1109 WERROR werr = WERR_SETUP_NOT_JOINED;
1110 bool createupn = False;
1111 const char *machineupn = NULL;
1112 const char *create_in_ou = NULL;
1114 const char *os_name = NULL;
1115 const char *os_version = NULL;
1117 nt_status = check_ads_config();
1118 if (!NT_STATUS_IS_OK(nt_status)) {
1119 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1120 werr = ntstatus_to_werror(nt_status);
1124 if (!(ctx = talloc_init("net_ads_join"))) {
1125 d_fprintf(stderr, "Could not initialise talloc context.\n");
1130 use_in_memory_ccache();
1132 werr = libnet_init_JoinCtx(ctx, &r);
1133 if (!W_ERROR_IS_OK(werr)) {
1137 /* process additional command line args */
1139 for ( i=0; i<argc; i++ ) {
1140 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1142 machineupn = get_string_param(argv[i]);
1144 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1145 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1146 d_fprintf(stderr, "Please supply a valid OU path.\n");
1147 werr = WERR_INVALID_PARAM;
1151 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1152 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1153 d_fprintf(stderr, "Please supply a operating system name.\n");
1154 werr = WERR_INVALID_PARAM;
1158 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1159 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1160 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1161 werr = WERR_INVALID_PARAM;
1170 /* Do the domain join here */
1172 r->in.domain_name = domain;
1173 r->in.create_upn = createupn;
1174 r->in.upn = machineupn;
1175 r->in.account_ou = create_in_ou;
1176 r->in.os_name = os_name;
1177 r->in.os_version = os_version;
1178 r->in.dc_name = opt_host;
1179 r->in.admin_account = opt_user_name;
1180 r->in.admin_password = net_prompt_pass(opt_user_name);
1181 r->in.debug = opt_verbose;
1182 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1183 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1184 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1186 werr = libnet_Join(ctx, r);
1187 if (!W_ERROR_IS_OK(werr)) {
1191 /* Check the short name of the domain */
1193 if (!strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1194 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1195 d_printf("domain name obtained from the server.\n");
1196 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1197 d_printf("You should set \"workgroup = %s\" in %s.\n",
1198 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1201 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1203 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1204 r->out.dns_domain_name);
1206 #if defined(WITH_DNS_UPDATES)
1208 /* We enter this block with user creds */
1209 ADS_STRUCT *ads_dns = NULL;
1211 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1212 /* kinit with the machine password */
1214 use_in_memory_ccache();
1215 asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1216 ads_dns->auth.password = secrets_fetch_machine_password(
1217 lp_workgroup(), NULL, NULL );
1218 ads_dns->auth.realm = SMB_STRDUP( lp_realm() );
1219 ads_kinit_password( ads_dns );
1222 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1223 d_fprintf( stderr, "DNS update failed!\n" );
1226 /* exit from this block using machine creds */
1227 ads_destroy(&ads_dns);
1236 /* issue an overall failure message at the end. */
1237 d_printf("Failed to join domain: %s\n",
1238 r && r->out.error_string ? r->out.error_string :
1239 get_friendly_werror_msg(werr));
1245 /*******************************************************************
1246 ********************************************************************/
1248 static int net_ads_dns_usage(int argc, const char **argv)
1250 #if defined(WITH_DNS_UPDATES)
1251 d_printf("net ads dns <command>\n");
1252 d_printf("Valid commands:\n");
1253 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1257 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1262 /*******************************************************************
1263 ********************************************************************/
1265 static int net_ads_dns_register(int argc, const char **argv)
1267 #if defined(WITH_DNS_UPDATES)
1273 talloc_enable_leak_report();
1277 d_fprintf(stderr, "net ads dns register\n");
1281 if (!(ctx = talloc_init("net_ads_dns"))) {
1282 d_fprintf(stderr, "Could not initialise talloc context\n");
1286 status = ads_startup(True, &ads);
1287 if ( !ADS_ERR_OK(status) ) {
1288 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1293 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1294 d_fprintf( stderr, "DNS update failed!\n" );
1295 ads_destroy( &ads );
1300 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1307 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1312 #if defined(WITH_DNS_UPDATES)
1313 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1316 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1318 #if defined(WITH_DNS_UPDATES)
1322 talloc_enable_leak_report();
1326 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1331 err = do_gethostbyname(argv[0], argv[1]);
1333 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1338 static int net_ads_dns(int argc, const char *argv[])
1340 struct functable func[] = {
1341 {"REGISTER", net_ads_dns_register},
1342 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1346 return net_run_function(argc, argv, func, net_ads_dns_usage);
1349 /*******************************************************************
1350 ********************************************************************/
1352 int net_ads_printer_usage(int argc, const char **argv)
1355 "\nnet ads printer search <printer>"
1356 "\n\tsearch for a printer in the directory\n"
1357 "\nnet ads printer info <printer> <server>"
1358 "\n\tlookup info in directory for printer on server"
1359 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1360 "\nnet ads printer publish <printername>"
1361 "\n\tpublish printer in directory"
1362 "\n\t(note: printer name is required)\n"
1363 "\nnet ads printer remove <printername>"
1364 "\n\tremove printer from directory"
1365 "\n\t(note: printer name is required)\n");
1369 /*******************************************************************
1370 ********************************************************************/
1372 static int net_ads_printer_search(int argc, const char **argv)
1376 LDAPMessage *res = NULL;
1378 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1382 rc = ads_find_printers(ads, &res);
1384 if (!ADS_ERR_OK(rc)) {
1385 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1386 ads_msgfree(ads, res);
1391 if (ads_count_replies(ads, res) == 0) {
1392 d_fprintf(stderr, "No results found\n");
1393 ads_msgfree(ads, res);
1399 ads_msgfree(ads, res);
1404 static int net_ads_printer_info(int argc, const char **argv)
1408 const char *servername, *printername;
1409 LDAPMessage *res = NULL;
1411 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1416 printername = argv[0];
1422 servername = argv[1];
1424 servername = global_myname();
1427 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1429 if (!ADS_ERR_OK(rc)) {
1430 d_fprintf(stderr, "Server '%s' not found: %s\n",
1431 servername, ads_errstr(rc));
1432 ads_msgfree(ads, res);
1437 if (ads_count_replies(ads, res) == 0) {
1438 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1439 ads_msgfree(ads, res);
1445 ads_msgfree(ads, res);
1451 static int net_ads_printer_publish(int argc, const char **argv)
1455 const char *servername, *printername;
1456 struct cli_state *cli;
1457 struct rpc_pipe_client *pipe_hnd;
1458 struct sockaddr_storage server_ss;
1460 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1461 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1462 char *prt_dn, *srv_dn, **srv_cn;
1463 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1464 LDAPMessage *res = NULL;
1466 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1467 talloc_destroy(mem_ctx);
1472 talloc_destroy(mem_ctx);
1473 return net_ads_printer_usage(argc, argv);
1476 printername = argv[0];
1479 servername = argv[1];
1481 servername = global_myname();
1484 /* Get printer data from SPOOLSS */
1486 resolve_name(servername, &server_ss, 0x20);
1488 nt_status = cli_full_connection(&cli, global_myname(), servername,
1491 opt_user_name, opt_workgroup,
1492 opt_password ? opt_password : "",
1493 CLI_FULL_CONNECTION_USE_KERBEROS,
1496 if (NT_STATUS_IS_ERR(nt_status)) {
1497 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1498 "for %s\n", servername, printername);
1500 talloc_destroy(mem_ctx);
1504 /* Publish on AD server */
1506 ads_find_machine_acct(ads, &res, servername);
1508 if (ads_count_replies(ads, res) == 0) {
1509 d_fprintf(stderr, "Could not find machine account for server %s\n",
1512 talloc_destroy(mem_ctx);
1516 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1517 srv_cn = ldap_explode_dn(srv_dn, 1);
1519 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1520 printername_escaped = escape_rdn_val_string_alloc(printername);
1521 if (!srv_cn_escaped || !printername_escaped) {
1522 SAFE_FREE(srv_cn_escaped);
1523 SAFE_FREE(printername_escaped);
1524 d_fprintf(stderr, "Internal error, out of memory!");
1526 talloc_destroy(mem_ctx);
1530 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1532 SAFE_FREE(srv_cn_escaped);
1533 SAFE_FREE(printername_escaped);
1535 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
1537 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1541 talloc_destroy(mem_ctx);
1545 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1549 talloc_destroy(mem_ctx);
1553 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1554 if (!ADS_ERR_OK(rc)) {
1555 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1558 talloc_destroy(mem_ctx);
1562 d_printf("published printer\n");
1565 talloc_destroy(mem_ctx);
1570 static int net_ads_printer_remove(int argc, const char **argv)
1574 const char *servername;
1576 LDAPMessage *res = NULL;
1578 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1583 return net_ads_printer_usage(argc, argv);
1587 servername = argv[1];
1589 servername = global_myname();
1592 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1594 if (!ADS_ERR_OK(rc)) {
1595 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1596 ads_msgfree(ads, res);
1601 if (ads_count_replies(ads, res) == 0) {
1602 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1603 ads_msgfree(ads, res);
1608 prt_dn = ads_get_dn(ads, res);
1609 ads_msgfree(ads, res);
1610 rc = ads_del_dn(ads, prt_dn);
1611 ads_memfree(ads, prt_dn);
1613 if (!ADS_ERR_OK(rc)) {
1614 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1623 static int net_ads_printer(int argc, const char **argv)
1625 struct functable func[] = {
1626 {"SEARCH", net_ads_printer_search},
1627 {"INFO", net_ads_printer_info},
1628 {"PUBLISH", net_ads_printer_publish},
1629 {"REMOVE", net_ads_printer_remove},
1633 return net_run_function(argc, argv, func, net_ads_printer_usage);
1637 static int net_ads_password(int argc, const char **argv)
1640 const char *auth_principal = opt_user_name;
1641 const char *auth_password = opt_password;
1643 char *new_password = NULL;
1648 if (opt_user_name == NULL || opt_password == NULL) {
1649 d_fprintf(stderr, "You must supply an administrator username/password\n");
1654 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1659 if (!strchr_m(user, '@')) {
1660 asprintf(&c, "%s@%s", argv[0], lp_realm());
1664 use_in_memory_ccache();
1665 c = strchr_m(auth_principal, '@');
1672 /* use the realm so we can eventually change passwords for users
1673 in realms other than default */
1674 if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
1678 /* we don't actually need a full connect, but it's the easy way to
1679 fill in the KDC's addresss */
1682 if (!ads || !ads->config.realm) {
1683 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1688 new_password = (char *)argv[1];
1690 asprintf(&prompt, "Enter new password for %s:", user);
1691 new_password = getpass(prompt);
1695 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1696 auth_password, user, new_password, ads->auth.time_offset);
1697 if (!ADS_ERR_OK(ret)) {
1698 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1703 d_printf("Password change for %s completed.\n", user);
1709 int net_ads_changetrustpw(int argc, const char **argv)
1712 char *host_principal;
1716 if (!secrets_init()) {
1717 DEBUG(1,("Failed to initialise secrets database\n"));
1721 net_use_krb_machine_account();
1723 use_in_memory_ccache();
1725 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1729 fstrcpy(my_name, global_myname());
1730 strlower_m(my_name);
1731 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1732 d_printf("Changing password for principal: %s\n", host_principal);
1734 ret = ads_change_trust_account_password(ads, host_principal);
1736 if (!ADS_ERR_OK(ret)) {
1737 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1739 SAFE_FREE(host_principal);
1743 d_printf("Password change for principal %s succeeded.\n", host_principal);
1745 if (lp_use_kerberos_keytab()) {
1746 d_printf("Attempting to update system keytab with new password.\n");
1747 if (ads_keytab_create_default(ads)) {
1748 d_printf("Failed to update system keytab.\n");
1753 SAFE_FREE(host_principal);
1759 help for net ads search
1761 static int net_ads_search_usage(int argc, const char **argv)
1764 "\nnet ads search <expression> <attributes...>\n"\
1765 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1766 "The expression is a standard LDAP search expression, and the\n"\
1767 "attributes are a list of LDAP fields to show in the results\n\n"\
1768 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1770 net_common_flags_usage(argc, argv);
1776 general ADS search function. Useful in diagnosing problems in ADS
1778 static int net_ads_search(int argc, const char **argv)
1782 const char *ldap_exp;
1784 LDAPMessage *res = NULL;
1787 return net_ads_search_usage(argc, argv);
1790 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1797 rc = ads_do_search_all(ads, ads->config.bind_path,
1799 ldap_exp, attrs, &res);
1800 if (!ADS_ERR_OK(rc)) {
1801 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1806 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1808 /* dump the results */
1811 ads_msgfree(ads, res);
1819 help for net ads search
1821 static int net_ads_dn_usage(int argc, const char **argv)
1824 "\nnet ads dn <dn> <attributes...>\n"\
1825 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1826 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
1827 "to show in the results\n\n"\
1828 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1829 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1831 net_common_flags_usage(argc, argv);
1837 general ADS search function. Useful in diagnosing problems in ADS
1839 static int net_ads_dn(int argc, const char **argv)
1845 LDAPMessage *res = NULL;
1848 return net_ads_dn_usage(argc, argv);
1851 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1858 rc = ads_do_search_all(ads, dn,
1860 "(objectclass=*)", attrs, &res);
1861 if (!ADS_ERR_OK(rc)) {
1862 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1867 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1869 /* dump the results */
1872 ads_msgfree(ads, res);
1879 help for net ads sid search
1881 static int net_ads_sid_usage(int argc, const char **argv)
1884 "\nnet ads sid <sid> <attributes...>\n"\
1885 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
1886 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
1887 "to show in the results\n\n"\
1888 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
1890 net_common_flags_usage(argc, argv);
1896 general ADS search function. Useful in diagnosing problems in ADS
1898 static int net_ads_sid(int argc, const char **argv)
1902 const char *sid_string;
1904 LDAPMessage *res = NULL;
1908 return net_ads_sid_usage(argc, argv);
1911 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1915 sid_string = argv[0];
1918 if (!string_to_sid(&sid, sid_string)) {
1919 d_fprintf(stderr, "could not convert sid\n");
1924 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
1925 if (!ADS_ERR_OK(rc)) {
1926 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1931 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1933 /* dump the results */
1936 ads_msgfree(ads, res);
1943 static int net_ads_keytab_usage(int argc, const char **argv)
1946 "net ads keytab <COMMAND>\n"\
1947 "<COMMAND> can be either:\n"\
1948 " ADD Adds new service principal\n"\
1949 " CREATE Creates a fresh keytab\n"\
1950 " FLUSH Flushes out all keytab entries\n"\
1951 " HELP Prints this help message\n"\
1952 " LIST List the keytab\n"\
1953 "The ADD and LIST command will take arguments, the other commands\n"\
1954 "will not take any arguments. The arguments given to ADD\n"\
1955 "should be a list of principals to add. For example, \n"\
1956 " net ads keytab add srv1 srv2\n"\
1957 "will add principals for the services srv1 and srv2 to the\n"\
1958 "system's keytab.\n"\
1959 "The LIST command takes a keytabname.\n"\
1965 static int net_ads_keytab_flush(int argc, const char **argv)
1970 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1973 ret = ads_keytab_flush(ads);
1978 static int net_ads_keytab_add(int argc, const char **argv)
1984 d_printf("Processing principals to add...\n");
1985 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1988 for (i = 0; i < argc; i++) {
1989 ret |= ads_keytab_add_entry(ads, argv[i]);
1995 static int net_ads_keytab_create(int argc, const char **argv)
2000 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2003 ret = ads_keytab_create_default(ads);
2008 static int net_ads_keytab_list(int argc, const char **argv)
2010 const char *keytab = NULL;
2016 return ads_keytab_list(keytab);
2020 int net_ads_keytab(int argc, const char **argv)
2022 struct functable func[] = {
2023 {"ADD", net_ads_keytab_add},
2024 {"CREATE", net_ads_keytab_create},
2025 {"FLUSH", net_ads_keytab_flush},
2026 {"HELP", net_ads_keytab_usage},
2027 {"LIST", net_ads_keytab_list},
2031 if (!lp_use_kerberos_keytab()) {
2032 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2033 use keytab functions.\n");
2036 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2039 static int net_ads_kerberos_usage(int argc, const char **argv)
2042 "net ads kerberos <COMMAND>\n"\
2043 "<COMMAND> can be either:\n"\
2044 " RENEW Renew TGT from existing credential cache\n"\
2045 " PAC Dumps the Kerberos PAC\n"\
2046 " KINIT Retrieve Ticket Granting Ticket (TGT)\n"\
2053 static int net_ads_kerberos_renew(int argc, const char **argv)
2055 int ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2057 d_printf("failed to renew kerberos ticket: %s\n",
2058 error_message(ret));
2063 static int net_ads_kerberos_pac(int argc, const char **argv)
2065 struct PAC_DATA *pac = NULL;
2066 struct PAC_LOGON_INFO *info = NULL;
2067 TALLOC_CTX *mem_ctx = NULL;
2071 mem_ctx = talloc_init("net_ads_kerberos_pac");
2076 opt_password = net_prompt_pass(opt_user_name);
2078 status = kerberos_return_pac(mem_ctx,
2087 2592000, /* one month */
2089 if (!NT_STATUS_IS_OK(status)) {
2090 d_printf("failed to query kerberos PAC: %s\n",
2095 info = get_logon_info_from_pac(pac);
2098 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2099 d_printf("The Pac: %s\n", s);
2104 TALLOC_FREE(mem_ctx);
2108 static int net_ads_kerberos_kinit(int argc, const char **argv)
2110 TALLOC_CTX *mem_ctx = NULL;
2114 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2119 opt_password = net_prompt_pass(opt_user_name);
2121 ret = kerberos_kinit_password_ext(opt_user_name,
2129 2592000, /* one month */
2132 d_printf("failed to kinit password: %s\n",
2139 int net_ads_kerberos(int argc, const char **argv)
2141 struct functable func[] = {
2142 {"KINIT", net_ads_kerberos_kinit},
2143 {"RENEW", net_ads_kerberos_renew},
2144 {"PAC", net_ads_kerberos_pac},
2145 {"HELP", net_ads_kerberos_usage},
2149 return net_run_function(argc, argv, func, net_ads_kerberos_usage);
2153 int net_ads_help(int argc, const char **argv)
2155 struct functable func[] = {
2156 {"USER", net_ads_user_usage},
2157 {"GROUP", net_ads_group_usage},
2158 {"PRINTER", net_ads_printer_usage},
2159 {"SEARCH", net_ads_search_usage},
2160 {"INFO", net_ads_info},
2161 {"JOIN", net_ads_join_usage},
2162 {"DNS", net_ads_dns_usage},
2163 {"LEAVE", net_ads_leave},
2164 {"STATUS", net_ads_status},
2165 {"PASSWORD", net_ads_password},
2166 {"CHANGETRUSTPW", net_ads_changetrustpw},
2170 return net_run_function(argc, argv, func, net_ads_usage);
2173 int net_ads(int argc, const char **argv)
2175 struct functable func[] = {
2176 {"INFO", net_ads_info},
2177 {"JOIN", net_ads_join},
2178 {"TESTJOIN", net_ads_testjoin},
2179 {"LEAVE", net_ads_leave},
2180 {"STATUS", net_ads_status},
2181 {"USER", net_ads_user},
2182 {"GROUP", net_ads_group},
2183 {"DNS", net_ads_dns},
2184 {"PASSWORD", net_ads_password},
2185 {"CHANGETRUSTPW", net_ads_changetrustpw},
2186 {"PRINTER", net_ads_printer},
2187 {"SEARCH", net_ads_search},
2189 {"SID", net_ads_sid},
2190 {"WORKGROUP", net_ads_workgroup},
2191 {"LOOKUP", net_ads_lookup},
2192 {"KEYTAB", net_ads_keytab},
2193 {"GPO", net_ads_gpo},
2194 {"KERBEROS", net_ads_kerberos},
2195 {"HELP", net_ads_help},
2199 return net_run_function(argc, argv, func, net_ads_usage);
2204 static int net_ads_noads(void)
2206 d_fprintf(stderr, "ADS support not compiled in\n");
2210 int net_ads_keytab(int argc, const char **argv)
2212 return net_ads_noads();
2215 int net_ads_kerberos(int argc, const char **argv)
2217 return net_ads_noads();
2220 int net_ads_usage(int argc, const char **argv)
2222 return net_ads_noads();
2225 int net_ads_help(int argc, const char **argv)
2227 return net_ads_noads();
2230 int net_ads_changetrustpw(int argc, const char **argv)
2232 return net_ads_noads();
2235 int net_ads_join(int argc, const char **argv)
2237 return net_ads_noads();
2240 int net_ads_user(int argc, const char **argv)
2242 return net_ads_noads();
2245 int net_ads_group(int argc, const char **argv)
2247 return net_ads_noads();
2250 /* this one shouldn't display a message */
2251 int net_ads_check(void)
2256 int net_ads_check_our_domain(void)
2261 int net_ads(int argc, const char **argv)
2263 return net_ads_usage(argc, argv);
2266 #endif /* WITH_ADS */