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"
28 int net_ads_usage(int argc, const char **argv)
30 d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
31 d_printf(" Join the local machine to a ADS realm\n");
33 d_printf(" Remove the local machine from a ADS realm\n");
34 d_printf("testjoin\n");
35 d_printf(" Validates the machine account in the domain\n");
37 d_printf(" List, add, or delete users in the realm\n");
39 d_printf(" List, add, or delete groups in the realm\n");
41 d_printf(" Displays details regarding a specific AD server\n");
43 d_printf(" Display details regarding the machine's account in AD\n");
45 d_printf(" Performs CLDAP query of AD domain controllers\n");
46 d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
47 d_printf(" Change a user's password using an admin account\n");
48 d_printf(" (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
49 d_printf("changetrustpw\n");
50 d_printf(" Change the trust account password of this machine in the AD tree\n");
51 d_printf("printer [info | publish | remove] <printername> <servername>\n");
52 d_printf(" Lookup, add, or remove directory entry for a printer\n");
53 d_printf("{search,dn,sid}\n");
54 d_printf(" Issue LDAP search queries using a general filter, by DN, or by SID\n");
56 d_printf(" Manage a local keytab file based on the machine account in AD\n");
58 d_printf(" Issue a dynamic DNS update request the server's hostname\n");
59 d_printf(" (using the machine credentials)\n");
64 /* when we do not have sufficient input parameters to contact a remote domain
65 * we always fall back to our own realm - Guenther*/
67 static const char *assume_own_realm(void)
69 if (!opt_host && strequal(lp_workgroup(), opt_target_workgroup)) {
77 do a cldap netlogon query
79 static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
81 struct cldap_netlogon_reply reply;
83 if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap.ip), ads->server.realm, &reply ) ) {
84 d_fprintf(stderr, "CLDAP query failed!\n");
88 d_printf("Information for Domain Controller: %s\n\n",
89 inet_ntoa(ads->ldap.ip));
91 d_printf("Response Type: ");
93 case SAMLOGON_AD_UNK_R:
94 d_printf("SAMLOGON\n");
97 d_printf("SAMLOGON_USER\n");
100 d_printf("0x%x\n", reply.type);
103 d_printf("GUID: %s\n",
104 smb_uuid_string_static(smb_uuid_unpack_static(reply.guid)));
107 "\tIs a GC of the forest: %s\n"
108 "\tIs an LDAP server: %s\n"
109 "\tSupports DS: %s\n"
110 "\tIs running a KDC: %s\n"
111 "\tIs running time services: %s\n"
112 "\tIs the closest DC: %s\n"
113 "\tIs writable: %s\n"
114 "\tHas a hardware clock: %s\n"
115 "\tIs a non-domain NC serviced by LDAP server: %s\n",
116 (reply.flags & ADS_PDC) ? "yes" : "no",
117 (reply.flags & ADS_GC) ? "yes" : "no",
118 (reply.flags & ADS_LDAP) ? "yes" : "no",
119 (reply.flags & ADS_DS) ? "yes" : "no",
120 (reply.flags & ADS_KDC) ? "yes" : "no",
121 (reply.flags & ADS_TIMESERV) ? "yes" : "no",
122 (reply.flags & ADS_CLOSEST) ? "yes" : "no",
123 (reply.flags & ADS_WRITABLE) ? "yes" : "no",
124 (reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
125 (reply.flags & ADS_NDNC) ? "yes" : "no");
127 printf("Forest:\t\t\t%s\n", reply.forest);
128 printf("Domain:\t\t\t%s\n", reply.domain);
129 printf("Domain Controller:\t%s\n", reply.hostname);
131 printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
132 printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
134 if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
135 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
137 printf("Server Site Name :\t\t%s\n", reply.server_site_name);
138 printf("Client Site Name :\t\t%s\n", reply.client_site_name);
140 d_printf("NT Version: %d\n", reply.version);
141 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
142 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
149 this implements the CLDAP based netlogon lookup requests
150 for finding the domain controller of a ADS domain
152 static int net_ads_lookup(int argc, const char **argv)
156 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
157 d_fprintf(stderr, "Didn't find the cldap server!\n");
161 if (!ads->config.realm) {
162 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
163 ads->ldap.port = 389;
166 return net_ads_cldap_netlogon(ads);
171 static int net_ads_info(int argc, const char **argv)
175 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
176 d_fprintf(stderr, "Didn't find the ldap server!\n");
180 if (!ads || !ads->config.realm) {
181 d_fprintf(stderr, "Didn't find the ldap server!\n");
185 /* Try to set the server's current time since we didn't do a full
186 TCP LDAP session initially */
188 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
189 d_fprintf( stderr, "Failed to get server's current time!\n");
192 d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap.ip));
193 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
194 d_printf("Realm: %s\n", ads->config.realm);
195 d_printf("Bind Path: %s\n", ads->config.bind_path);
196 d_printf("LDAP port: %d\n", ads->ldap.port);
197 d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
199 d_printf("KDC server: %s\n", ads->auth.kdc_server );
200 d_printf("Server time offset: %d\n", ads->auth.time_offset );
205 static void use_in_memory_ccache(void) {
206 /* Use in-memory credentials cache so we do not interfere with
207 * existing credentials */
208 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
211 static ADS_STATUS ads_startup_int(BOOL only_own_domain, uint32 auth_flags, ADS_STRUCT **ads_ret)
213 ADS_STRUCT *ads = NULL;
215 BOOL need_password = False;
216 BOOL second_time = False;
218 const char *realm = NULL;
219 BOOL tried_closest_dc = False;
221 /* lp_realm() should be handled by a command line param,
222 However, the join requires that realm be set in smb.conf
223 and compares our realm with the remote server's so this is
224 ok until someone needs more flexibility */
229 if (only_own_domain) {
232 realm = assume_own_realm();
235 ads = ads_init(realm, opt_target_workgroup, opt_host);
237 if (!opt_user_name) {
238 opt_user_name = "administrator";
241 if (opt_user_specified) {
242 need_password = True;
246 if (!opt_password && need_password && !opt_machine_pass) {
247 opt_password = net_prompt_pass(opt_user_name);
250 return ADS_ERROR(LDAP_NO_MEMORY);
255 use_in_memory_ccache();
256 SAFE_FREE(ads->auth.password);
257 ads->auth.password = smb_xstrdup(opt_password);
260 ads->auth.flags |= auth_flags;
261 SAFE_FREE(ads->auth.user_name);
262 ads->auth.user_name = smb_xstrdup(opt_user_name);
265 * If the username is of the form "name@realm",
266 * extract the realm and convert to upper case.
267 * This is only used to establish the connection.
269 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
271 SAFE_FREE(ads->auth.realm);
272 ads->auth.realm = smb_xstrdup(cp);
273 strupper_m(ads->auth.realm);
276 status = ads_connect(ads);
278 if (!ADS_ERR_OK(status)) {
280 if (NT_STATUS_EQUAL(ads_ntstatus(status),
281 NT_STATUS_NO_LOGON_SERVERS)) {
282 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
287 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
288 need_password = True;
297 /* when contacting our own domain, make sure we use the closest DC.
298 * This is done by reconnecting to ADS because only the first call to
299 * ads_connect will give us our own sitename */
301 if ((only_own_domain || !opt_host) && !tried_closest_dc) {
303 tried_closest_dc = True; /* avoid loop */
305 if (!ads->config.tried_closest_dc) {
307 namecache_delete(ads->server.realm, 0x1C);
308 namecache_delete(ads->server.workgroup, 0x1C);
321 ADS_STATUS ads_startup(BOOL only_own_domain, ADS_STRUCT **ads)
323 return ads_startup_int(only_own_domain, 0, ads);
326 ADS_STATUS ads_startup_nobind(BOOL only_own_domain, ADS_STRUCT **ads)
328 return ads_startup_int(only_own_domain, ADS_AUTH_NO_BIND, ads);
332 Check to see if connection can be made via ads.
333 ads_startup() stores the password in opt_password if it needs to so
334 that rpc or rap can use it without re-prompting.
336 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
341 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
345 ads->auth.flags |= ADS_AUTH_NO_BIND;
347 status = ads_connect(ads);
348 if ( !ADS_ERR_OK(status) ) {
356 int net_ads_check_our_domain(void)
358 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
361 int net_ads_check(void)
363 return net_ads_check_int(NULL, opt_workgroup, opt_host);
366 determine the netbios workgroup name for a domain
368 static int net_ads_workgroup(int argc, const char **argv)
371 struct cldap_netlogon_reply reply;
373 if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
374 d_fprintf(stderr, "Didn't find the cldap server!\n");
378 if (!ads->config.realm) {
379 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
380 ads->ldap.port = 389;
383 if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap.ip), ads->server.realm, &reply ) ) {
384 d_fprintf(stderr, "CLDAP query failed!\n");
388 d_printf("Workgroup: %s\n", reply.netbios_domain);
397 static BOOL usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
399 char **disp_fields = (char **) data_area;
401 if (!field) { /* must be end of record */
402 if (disp_fields[0]) {
403 if (!strchr_m(disp_fields[0], '$')) {
405 d_printf("%-21.21s %s\n",
406 disp_fields[0], disp_fields[1]);
408 d_printf("%s\n", disp_fields[0]);
411 SAFE_FREE(disp_fields[0]);
412 SAFE_FREE(disp_fields[1]);
415 if (!values) /* must be new field, indicate string field */
417 if (StrCaseCmp(field, "sAMAccountName") == 0) {
418 disp_fields[0] = SMB_STRDUP((char *) values[0]);
420 if (StrCaseCmp(field, "description") == 0)
421 disp_fields[1] = SMB_STRDUP((char *) values[0]);
425 static int net_ads_user_usage(int argc, const char **argv)
427 return net_help_user(argc, argv);
430 static int ads_user_add(int argc, const char **argv)
435 LDAPMessage *res=NULL;
439 if (argc < 1) return net_ads_user_usage(argc, argv);
441 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
445 status = ads_find_user_acct(ads, &res, argv[0]);
447 if (!ADS_ERR_OK(status)) {
448 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
452 if (ads_count_replies(ads, res)) {
453 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
458 ou_str = SMB_STRDUP(opt_container);
460 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
463 status = ads_add_user_acct(ads, argv[0], ou_str, opt_comment);
465 if (!ADS_ERR_OK(status)) {
466 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
471 /* if no password is to be set, we're done */
473 d_printf("User %s added\n", argv[0]);
478 /* try setting the password */
479 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
480 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
481 ads->auth.time_offset);
483 if (ADS_ERR_OK(status)) {
484 d_printf("User %s added\n", argv[0]);
489 /* password didn't set, delete account */
490 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
491 argv[0], ads_errstr(status));
492 ads_msgfree(ads, res);
493 status=ads_find_user_acct(ads, &res, argv[0]);
494 if (ADS_ERR_OK(status)) {
495 userdn = ads_get_dn(ads, res);
496 ads_del_dn(ads, userdn);
497 ads_memfree(ads, userdn);
502 ads_msgfree(ads, res);
508 static int ads_user_info(int argc, const char **argv)
513 const char *attrs[] = {"memberOf", NULL};
514 char *searchstring=NULL;
519 return net_ads_user_usage(argc, argv);
522 escaped_user = escape_ldap_string_alloc(argv[0]);
525 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
529 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
530 SAFE_FREE(escaped_user);
534 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
535 rc = ads_search(ads, &res, searchstring, attrs);
536 safe_free(searchstring);
538 if (!ADS_ERR_OK(rc)) {
539 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
541 SAFE_FREE(escaped_user);
545 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
546 (LDAPMessage *)res, "memberOf");
551 for (i=0;grouplist[i];i++) {
552 groupname = ldap_explode_dn(grouplist[i], 1);
553 d_printf("%s\n", groupname[0]);
554 ldap_value_free(groupname);
556 ldap_value_free(grouplist);
559 ads_msgfree(ads, res);
561 SAFE_FREE(escaped_user);
565 static int ads_user_delete(int argc, const char **argv)
569 LDAPMessage *res = NULL;
573 return net_ads_user_usage(argc, argv);
576 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
580 rc = ads_find_user_acct(ads, &res, argv[0]);
581 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
582 d_printf("User %s does not exist.\n", argv[0]);
583 ads_msgfree(ads, res);
587 userdn = ads_get_dn(ads, res);
588 ads_msgfree(ads, res);
589 rc = ads_del_dn(ads, userdn);
590 ads_memfree(ads, userdn);
591 if (ADS_ERR_OK(rc)) {
592 d_printf("User %s deleted\n", argv[0]);
596 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
602 int net_ads_user(int argc, const char **argv)
604 struct functable func[] = {
605 {"ADD", ads_user_add},
606 {"INFO", ads_user_info},
607 {"DELETE", ads_user_delete},
612 const char *shortattrs[] = {"sAMAccountName", NULL};
613 const char *longattrs[] = {"sAMAccountName", "description", NULL};
614 char *disp_fields[2] = {NULL, NULL};
617 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
621 if (opt_long_list_entries)
622 d_printf("\nUser name Comment"\
623 "\n-----------------------------\n");
625 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
627 "(objectCategory=user)",
628 opt_long_list_entries ? longattrs :
629 shortattrs, usergrp_display,
632 return ADS_ERR_OK(rc) ? 0 : -1;
635 return net_run_function(argc, argv, func, net_ads_user_usage);
638 static int net_ads_group_usage(int argc, const char **argv)
640 return net_help_group(argc, argv);
643 static int ads_group_add(int argc, const char **argv)
647 LDAPMessage *res=NULL;
652 return net_ads_group_usage(argc, argv);
655 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
659 status = ads_find_user_acct(ads, &res, argv[0]);
661 if (!ADS_ERR_OK(status)) {
662 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
666 if (ads_count_replies(ads, res)) {
667 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
672 ou_str = SMB_STRDUP(opt_container);
674 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
677 status = ads_add_group_acct(ads, argv[0], ou_str, opt_comment);
679 if (ADS_ERR_OK(status)) {
680 d_printf("Group %s added\n", argv[0]);
683 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
689 ads_msgfree(ads, res);
695 static int ads_group_delete(int argc, const char **argv)
699 LDAPMessage *res = NULL;
703 return net_ads_group_usage(argc, argv);
706 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
710 rc = ads_find_user_acct(ads, &res, argv[0]);
711 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
712 d_printf("Group %s does not exist.\n", argv[0]);
713 ads_msgfree(ads, res);
717 groupdn = ads_get_dn(ads, res);
718 ads_msgfree(ads, res);
719 rc = ads_del_dn(ads, groupdn);
720 ads_memfree(ads, groupdn);
721 if (ADS_ERR_OK(rc)) {
722 d_printf("Group %s deleted\n", argv[0]);
726 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
732 int net_ads_group(int argc, const char **argv)
734 struct functable func[] = {
735 {"ADD", ads_group_add},
736 {"DELETE", ads_group_delete},
741 const char *shortattrs[] = {"sAMAccountName", NULL};
742 const char *longattrs[] = {"sAMAccountName", "description", NULL};
743 char *disp_fields[2] = {NULL, NULL};
746 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
750 if (opt_long_list_entries)
751 d_printf("\nGroup name Comment"\
752 "\n-----------------------------\n");
753 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
755 "(objectCategory=group)",
756 opt_long_list_entries ? longattrs :
757 shortattrs, usergrp_display,
761 return ADS_ERR_OK(rc) ? 0 : -1;
763 return net_run_function(argc, argv, func, net_ads_group_usage);
766 static int net_ads_status(int argc, const char **argv)
772 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
776 rc = ads_find_machine_acct(ads, &res, global_myname());
777 if (!ADS_ERR_OK(rc)) {
778 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
783 if (ads_count_replies(ads, res) == 0) {
784 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
794 /*******************************************************************
795 Leave an AD domain. Windows XP disables the machine account.
796 We'll try the same. The old code would do an LDAP delete.
797 That only worked using the machine creds because added the machine
798 with full control to the computer object's ACL.
799 *******************************************************************/
801 static int net_ads_leave(int argc, const char **argv)
803 ADS_STRUCT *ads = NULL;
807 struct cli_state *cli = NULL;
809 DOM_SID *dom_sid = NULL;
810 char *short_domain_name = NULL;
812 if (!secrets_init()) {
813 DEBUG(1,("Failed to initialise secrets database\n"));
817 if (!(ctx = talloc_init("net_ads_leave"))) {
818 d_fprintf(stderr, "Could not initialise talloc context.\n");
822 /* The finds a DC and takes care of getting the
823 user creds if necessary */
825 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
829 /* make RPC calls here */
831 if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, &ads->ldap.ip,
832 ads->config.ldap_server_name)) )
837 if ( !NT_STATUS_IS_OK(netdom_get_domain_sid( ctx, cli, &short_domain_name, &dom_sid )) ) {
841 saf_delete( short_domain_name );
843 status = netdom_leave_domain(ctx, cli, dom_sid);
845 /* Try and delete it via LDAP - the old way we used to. */
847 adsret = ads_leave_realm(ads, global_myname());
848 if (ADS_ERR_OK(adsret)) {
849 d_printf("Deleted account for '%s' in realm '%s'\n",
850 global_myname(), ads->config.realm);
853 /* We couldn't delete it - see if the disable succeeded. */
854 if (NT_STATUS_IS_OK(status)) {
855 d_printf("Disabled account for '%s' in realm '%s'\n",
856 global_myname(), ads->config.realm);
859 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
860 global_myname(), ads->config.realm);
875 static NTSTATUS net_ads_join_ok(void)
877 ADS_STRUCT *ads = NULL;
880 if (!secrets_init()) {
881 DEBUG(1,("Failed to initialise secrets database\n"));
882 return NT_STATUS_ACCESS_DENIED;
885 net_use_krb_machine_account();
887 status = ads_startup(True, &ads);
888 if (!ADS_ERR_OK(status)) {
889 return ads_ntstatus(status);
897 check that an existing join is OK
899 int net_ads_testjoin(int argc, const char **argv)
902 use_in_memory_ccache();
904 /* Display success or failure */
905 status = net_ads_join_ok();
906 if (!NT_STATUS_IS_OK(status)) {
907 fprintf(stderr,"Join to domain is not valid: %s\n",
908 get_friendly_nt_error_msg(status));
912 printf("Join is OK\n");
916 /*******************************************************************
917 Simple configu checks before beginning the join
918 ********************************************************************/
920 static NTSTATUS check_ads_config( void )
922 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
923 d_printf("Host is not configured as a member server.\n");
924 return NT_STATUS_INVALID_DOMAIN_ROLE;
927 if (strlen(global_myname()) > 15) {
928 d_printf("Our netbios name can be at most 15 chars long, "
929 "\"%s\" is %u chars long\n", global_myname(),
930 (unsigned int)strlen(global_myname()));
931 return NT_STATUS_NAME_TOO_LONG;
934 if ( lp_security() == SEC_ADS && !*lp_realm()) {
935 d_fprintf(stderr, "realm must be set in in %s for ADS "
936 "join to succeed.\n", dyn_CONFIGFILE);
937 return NT_STATUS_INVALID_PARAMETER;
940 if (!secrets_init()) {
941 DEBUG(1,("Failed to initialise secrets database\n"));
942 /* This is a good bet for failure of secrets_init ... */
943 return NT_STATUS_ACCESS_DENIED;
949 /*******************************************************************
951 ********************************************************************/
953 static NTSTATUS net_join_domain(TALLOC_CTX *ctx, const char *servername,
954 struct in_addr *ip, char **domain,
956 const char *password)
958 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
959 struct cli_state *cli = NULL;
961 ret = connect_to_ipc_krb5(&cli, ip, servername);
962 if ( !NT_STATUS_IS_OK(ret) ) {
966 ret = netdom_get_domain_sid( ctx, cli, domain, dom_sid );
967 if ( !NT_STATUS_IS_OK(ret) ) {
971 /* cli->server_domain is not filled in when using krb5
974 saf_store( *domain, cli->desthost );
976 ret = netdom_join_domain( ctx, cli, *dom_sid, password, ND_TYPE_AD );
985 /*******************************************************************
986 Set a machines dNSHostName and servicePrincipalName attributes
987 ********************************************************************/
989 static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
991 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
994 const char *servicePrincipalName[3] = {NULL, NULL, NULL};
997 LDAPMessage *res = NULL;
998 char *dn_string = NULL;
999 const char *machine_name = global_myname();
1002 if ( !machine_name ) {
1003 return ADS_ERROR(LDAP_NO_MEMORY);
1008 status = ads_find_machine_acct(ads_s, &res, machine_name);
1009 if (!ADS_ERR_OK(status))
1012 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1013 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1014 return ADS_ERROR(LDAP_NO_MEMORY);
1017 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1018 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1022 new_dn = talloc_strdup(ctx, dn_string);
1023 ads_memfree(ads_s, dn_string);
1025 return ADS_ERROR(LDAP_NO_MEMORY);
1028 /* Windows only creates HOST/shortname & HOST/fqdn. */
1030 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) )
1033 servicePrincipalName[0] = psp;
1035 name_to_fqdn(my_fqdn, machine_name);
1036 strlower_m(my_fqdn);
1037 if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) )
1039 servicePrincipalName[1] = psp;
1041 if (!(mods = ads_init_mods(ctx))) {
1045 /* fields of primary importance */
1047 ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
1048 ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
1050 status = ads_gen_mod(ads_s, new_dn, mods);
1053 ads_msgfree(ads_s, res);
1058 /*******************************************************************
1059 Set a machines dNSHostName and servicePrincipalName attributes
1060 ********************************************************************/
1062 static ADS_STATUS net_set_machine_upn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, const char *upn )
1064 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1067 LDAPMessage *res = NULL;
1068 char *dn_string = NULL;
1069 const char *machine_name = global_myname();
1072 if ( !machine_name ) {
1073 return ADS_ERROR(LDAP_NO_MEMORY);
1078 status = ads_find_machine_acct(ads_s, &res, machine_name);
1079 if (!ADS_ERR_OK(status))
1082 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1083 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1084 return ADS_ERROR(LDAP_NO_MEMORY);
1087 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1088 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1092 new_dn = talloc_strdup(ctx, dn_string);
1093 ads_memfree(ads_s, dn_string);
1095 return ADS_ERROR(LDAP_NO_MEMORY);
1098 /* now do the mods */
1100 if (!(mods = ads_init_mods(ctx))) {
1104 /* fields of primary importance */
1106 ads_mod_str(ctx, &mods, "userPrincipalName", upn);
1108 status = ads_gen_mod(ads_s, new_dn, mods);
1111 ads_msgfree(ads_s, res);
1116 /*******************************************************************
1117 Set a machines dNSHostName and servicePrincipalName attributes
1118 ********************************************************************/
1120 static ADS_STATUS net_set_os_attributes(TALLOC_CTX *ctx, ADS_STRUCT *ads_s,
1121 const char *os_name, const char *os_version )
1123 ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
1126 LDAPMessage *res = NULL;
1127 char *dn_string = NULL;
1128 const char *machine_name = global_myname();
1132 if ( !os_name || !os_version ) {
1133 return ADS_ERROR(LDAP_NO_MEMORY);
1138 status = ads_find_machine_acct(ads_s, &res, machine_name);
1139 if (!ADS_ERR_OK(status))
1142 if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
1143 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1144 return ADS_ERROR(LDAP_NO_MEMORY);
1147 if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
1148 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
1152 new_dn = talloc_strdup(ctx, dn_string);
1153 ads_memfree(ads_s, dn_string);
1155 return ADS_ERROR(LDAP_NO_MEMORY);
1158 /* now do the mods */
1160 if (!(mods = ads_init_mods(ctx))) {
1164 os_sp = talloc_asprintf( ctx, "Samba %s", SAMBA_VERSION_STRING );
1166 /* fields of primary importance */
1168 ads_mod_str(ctx, &mods, "operatingSystem", os_name);
1169 ads_mod_str(ctx, &mods, "operatingSystemVersion", os_version);
1171 ads_mod_str(ctx, &mods, "operatingSystemServicePack", os_sp);
1173 status = ads_gen_mod(ads_s, new_dn, mods);
1176 ads_msgfree(ads_s, res);
1177 TALLOC_FREE( os_sp );
1182 /*******************************************************************
1183 join a domain using ADS (LDAP mods)
1184 ********************************************************************/
1186 static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
1188 ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
1189 char *ou_str = NULL;
1191 LDAPMessage *res = NULL;
1194 ou_str = ads_ou_string(ads, ou);
1195 if (asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path) == -1) {
1196 rc = ADS_ERROR(LDAP_NO_MEMORY);
1200 rc = ads_search_dn(ads, &res, dn, NULL);
1201 if (!ADS_ERR_OK(rc)) {
1202 d_fprintf(stderr, "The specified OU does not exist.\n");
1206 /* Attempt to create the machine account and bail if this fails.
1207 Assume that the admin wants exactly what they requested */
1209 rc = ads_create_machine_acct( ads, global_myname(), dn );
1210 if (ADS_ERR_OK(rc)) {
1211 DEBUG(1, ("machine account created\n"));
1214 if ( !(rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS) ) {
1215 DEBUG(1, ("machine account creation failed\n"));
1219 rc = ads_move_machine_acct(ads, global_myname(), dn, &moved);
1220 if (!ADS_ERR_OK(rc)) {
1221 DEBUG(1, ("failure to locate/move pre-existing machine account\n"));
1226 d_printf("The machine account was moved into the specified OU.\n");
1228 d_printf("The machine account already exists in the specified OU.\n");
1232 ads_msgfree(ads, res);
1233 SAFE_FREE( ou_str );
1239 /************************************************************************
1240 ************************************************************************/
1242 static BOOL net_derive_salting_principal( TALLOC_CTX *ctx, ADS_STRUCT *ads )
1248 LDAPMessage *res = NULL;
1249 const char *machine_name = global_myname();
1251 status = ads_domain_func_level( ads, &domain_func );
1252 if ( !ADS_ERR_OK(status) ) {
1253 DEBUG(2,("Failed to determine domain functional level!\n"));
1257 /* go ahead and setup the default salt */
1259 if ( (std_salt = kerberos_standard_des_salt()) == NULL ) {
1260 d_fprintf(stderr, "net_derive_salting_principal: failed to obtain stanard DES salt\n");
1264 fstrcpy( salt, std_salt );
1265 SAFE_FREE( std_salt );
1267 /* if it's a Windows functional domain, we have to look for the UPN */
1269 if ( domain_func == DS_DOMAIN_FUNCTION_2000 ) {
1273 status = ads_find_machine_acct(ads, &res, machine_name);
1274 if (!ADS_ERR_OK(status)) {
1278 if ( (count = ads_count_replies(ads, res)) != 1 ) {
1279 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
1283 upn = ads_pull_string(ads, ctx, res, "userPrincipalName");
1285 fstrcpy( salt, upn );
1288 ads_msgfree(ads, res);
1291 return kerberos_secrets_store_des_salt( salt );
1294 /*******************************************************************
1295 Send a DNS update request
1296 *******************************************************************/
1298 #if defined(WITH_DNS_UPDATES)
1300 DNS_ERROR DoDNSUpdate(char *pszServerName,
1301 const char *pszDomainName,
1302 const char *pszHostName,
1303 const struct in_addr *iplist, int num_addrs );
1306 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1307 const char *machine_name,
1308 const struct in_addr *addrs,
1311 struct dns_rr_ns *nameservers = NULL;
1313 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1316 const char *dnsdomain = NULL;
1317 char *root_domain = NULL;
1319 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1320 d_printf("No DNS domain configured for %s. "
1321 "Unable to perform DNS Update.\n", machine_name);
1322 status = NT_STATUS_INVALID_PARAMETER;
1327 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1328 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1329 /* Child domains often do not have NS records. Look
1330 for the NS record for the forest root domain
1331 (rootDomainNamingContext in therootDSE) */
1333 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1334 LDAPMessage *msg = NULL;
1336 ADS_STATUS ads_status;
1338 if ( !ads->ldap.ld ) {
1339 ads_status = ads_connect( ads );
1340 if ( !ADS_ERR_OK(ads_status) ) {
1341 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1346 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1347 "(objectclass=*)", rootname_attrs, &msg);
1348 if (!ADS_ERR_OK(ads_status)) {
1352 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1354 ads_msgfree( ads, msg );
1358 root_domain = ads_build_domain( root_dn );
1361 ads_msgfree( ads, msg );
1363 /* try again for NS servers */
1365 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1367 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1368 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1369 "realm\n", ads->config.realm));
1373 dnsdomain = root_domain;
1377 /* Now perform the dns update - we'll try non-secure and if we fail,
1378 we'll follow it up with a secure update */
1380 fstrcpy( dns_server, nameservers[0].hostname );
1382 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1383 if (!ERR_DNS_IS_OK(dns_err)) {
1384 status = NT_STATUS_UNSUCCESSFUL;
1389 SAFE_FREE( root_domain );
1394 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1397 struct in_addr *iplist = NULL;
1398 fstring machine_name;
1401 name_to_fqdn( machine_name, global_myname() );
1402 strlower_m( machine_name );
1404 /* Get our ip address (not the 127.0.0.x address but a real ip
1407 num_addrs = get_my_ip_address( &iplist );
1408 if ( num_addrs <= 0 ) {
1409 DEBUG(4,("net_ads_join: Failed to find my non-loopback IP "
1411 return NT_STATUS_INVALID_PARAMETER;
1414 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1416 SAFE_FREE( iplist );
1422 /*******************************************************************
1423 utility function to parse an integer parameter from
1425 **********************************************************/
1426 static char* get_string_param( const char* param )
1430 if ( (p = strchr( param, '=' )) == NULL )
1436 /*******************************************************************
1437 ********************************************************************/
1439 static int net_ads_join_usage(int argc, const char **argv)
1441 d_printf("net ads join [options]\n");
1442 d_printf("Valid options:\n");
1443 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1444 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1445 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1446 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1447 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1448 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1449 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1450 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1451 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1452 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1453 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1454 d_printf(" the two other attributes.\n");
1459 /*******************************************************************
1460 ********************************************************************/
1462 int net_ads_join(int argc, const char **argv)
1464 ADS_STRUCT *ads = NULL;
1467 char *machine_account = NULL;
1468 char *short_domain_name = NULL;
1469 char *tmp_password, *password;
1470 TALLOC_CTX *ctx = NULL;
1471 DOM_SID *domain_sid = NULL;
1472 BOOL createupn = False;
1473 const char *machineupn = NULL;
1474 const char *create_in_ou = NULL;
1477 struct in_addr dcip;
1478 const char *os_name = NULL;
1479 const char *os_version = NULL;
1481 nt_status = check_ads_config();
1482 if (!NT_STATUS_IS_OK(nt_status)) {
1483 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1487 /* find a DC to initialize the server affinity cache */
1489 get_dc_name( lp_workgroup(), lp_realm(), dc_name, &dcip );
1491 status = ads_startup(True, &ads);
1492 if (!ADS_ERR_OK(status)) {
1493 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1494 nt_status = ads_ntstatus(status);
1498 if (strcmp(ads->config.realm, lp_realm()) != 0) {
1499 d_fprintf(stderr, "realm of remote server (%s) and realm in %s "
1500 "(%s) DO NOT match. Aborting join\n", ads->config.realm,
1501 dyn_CONFIGFILE, lp_realm());
1502 nt_status = NT_STATUS_INVALID_PARAMETER;
1506 if (!(ctx = talloc_init("net_ads_join"))) {
1507 d_fprintf(stderr, "Could not initialise talloc context.\n");
1508 nt_status = NT_STATUS_NO_MEMORY;
1512 /* process additional command line args */
1514 for ( i=0; i<argc; i++ ) {
1515 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1517 machineupn = get_string_param(argv[i]);
1519 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1520 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1521 d_fprintf(stderr, "Please supply a valid OU path.\n");
1522 nt_status = NT_STATUS_INVALID_PARAMETER;
1526 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1527 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1528 d_fprintf(stderr, "Please supply a operating system name.\n");
1529 nt_status = NT_STATUS_INVALID_PARAMETER;
1533 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1534 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1535 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1536 nt_status = NT_STATUS_INVALID_PARAMETER;
1541 d_fprintf(stderr, "Bad option: %s\n", argv[i]);
1542 nt_status = NT_STATUS_INVALID_PARAMETER;
1547 /* If we were given an OU, try to create the machine in
1548 the OU account first and then do the normal RPC join */
1550 if ( create_in_ou ) {
1551 status = net_precreate_machine_acct( ads, create_in_ou );
1552 if ( !ADS_ERR_OK(status) ) {
1553 d_fprintf( stderr, "Failed to pre-create the machine object "
1554 "in OU %s.\n", create_in_ou);
1555 DEBUG(1, ("error calling net_precreate_machine_acct: %s\n",
1556 ads_errstr(status)));
1557 nt_status = ads_ntstatus(status);
1562 /* Do the domain join here */
1564 tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1565 password = talloc_strdup(ctx, tmp_password);
1567 nt_status = net_join_domain(ctx, ads->config.ldap_server_name,
1568 &ads->ldap.ip, &short_domain_name, &domain_sid, password);
1569 if ( !NT_STATUS_IS_OK(nt_status) ) {
1570 DEBUG(1, ("call of net_join_domain failed: %s\n",
1571 get_friendly_nt_error_msg(nt_status)));
1575 /* Check the short name of the domain */
1577 if ( !strequal(lp_workgroup(), short_domain_name) ) {
1578 d_printf("The workgroup in %s does not match the short\n", dyn_CONFIGFILE);
1579 d_printf("domain name obtained from the server.\n");
1580 d_printf("Using the name [%s] from the server.\n", short_domain_name);
1581 d_printf("You should set \"workgroup = %s\" in %s.\n",
1582 short_domain_name, dyn_CONFIGFILE);
1585 d_printf("Using short domain name -- %s\n", short_domain_name);
1587 /* HACK ALERT! Store the sid and password under both the lp_workgroup()
1588 value from smb.conf and the string returned from the server. The former is
1589 neede to bootstrap winbindd's first connection to the DC to get the real
1590 short domain name --jerry */
1592 if ( (netdom_store_machine_account( lp_workgroup(), domain_sid, password ) == -1)
1593 || (netdom_store_machine_account( short_domain_name, domain_sid, password ) == -1) )
1595 /* issue an internal error here for now.
1596 * everything else would mean changing tdb routines. */
1597 nt_status = NT_STATUS_INTERNAL_ERROR;
1601 /* Verify that everything is ok */
1603 if ( net_rpc_join_ok(short_domain_name, ads->config.ldap_server_name, &ads->ldap.ip) != 0 ) {
1604 d_fprintf(stderr, "Failed to verify membership in domain!\n");
1608 /* create the dNSHostName & servicePrincipalName values */
1610 status = net_set_machine_spn( ctx, ads );
1611 if ( !ADS_ERR_OK(status) ) {
1613 d_fprintf(stderr, "Failed to set servicePrincipalNames. Please ensure that\n");
1614 d_fprintf(stderr, "the DNS domain of this server matches the AD domain,\n");
1615 d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n");
1617 /* Disable the machine account in AD. Better to fail than to leave
1618 a confused admin. */
1620 if ( net_ads_leave( 0, NULL ) != 0 ) {
1621 d_fprintf( stderr, "Failed to disable machine account in AD. Please do so manually.\n");
1624 /* clear out the machine password */
1626 netdom_store_machine_account( lp_workgroup(), domain_sid, "" );
1627 netdom_store_machine_account( short_domain_name, domain_sid, "" );
1629 nt_status = ads_ntstatus(status);
1633 if ( !net_derive_salting_principal( ctx, ads ) ) {
1634 DEBUG(1,("Failed to determine salting principal\n"));
1641 /* default to using the short UPN name */
1642 if ( !machineupn ) {
1643 snprintf( upn, sizeof(upn), "host/%s@%s", global_myname(),
1644 ads->config.realm );
1648 status = net_set_machine_upn( ctx, ads, machineupn );
1649 if ( !ADS_ERR_OK(status) ) {
1650 d_fprintf(stderr, "Failed to set userPrincipalName. Are you a Domain Admin?\n");
1654 /* Try to set the operatingSystem attributes if asked */
1656 if ( os_name && os_version ) {
1657 status = net_set_os_attributes( ctx, ads, os_name, os_version );
1658 if ( !ADS_ERR_OK(status) ) {
1659 d_fprintf(stderr, "Failed to set operatingSystem attributes. "
1660 "Are you a Domain Admin?\n");
1664 /* Now build the keytab, using the same ADS connection */
1666 if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
1667 DEBUG(1,("Error creating host keytab!\n"));
1670 #if defined(WITH_DNS_UPDATES)
1671 /* We enter this block with user creds */
1672 ads_kdestroy( NULL );
1676 if ( (ads = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1677 /* kinit with the machine password */
1679 use_in_memory_ccache();
1680 asprintf( &ads->auth.user_name, "%s$", global_myname() );
1681 ads->auth.password = secrets_fetch_machine_password(
1682 lp_workgroup(), NULL, NULL );
1683 ads->auth.realm = SMB_STRDUP( lp_realm() );
1684 ads_kinit_password( ads );
1687 if ( !ads || !NT_STATUS_IS_OK(net_update_dns( ctx, ads )) ) {
1688 d_fprintf( stderr, "DNS update failed!\n" );
1691 /* exit from this block using machine creds */
1694 d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->server.realm);
1696 SAFE_FREE(machine_account);
1703 /* issue an overall failure message at the end. */
1704 d_printf("Failed to join domain: %s\n", get_friendly_nt_error_msg(nt_status));
1706 SAFE_FREE(machine_account);
1714 /*******************************************************************
1715 ********************************************************************/
1717 static int net_ads_dns_usage(int argc, const char **argv)
1719 #if defined(WITH_DNS_UPDATES)
1720 d_printf("net ads dns <command>\n");
1721 d_printf("Valid commands:\n");
1722 d_printf(" register Issue a dynamic DNS update request for our hostname\n");
1726 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1731 /*******************************************************************
1732 ********************************************************************/
1734 static int net_ads_dns_register(int argc, const char **argv)
1736 #if defined(WITH_DNS_UPDATES)
1742 talloc_enable_leak_report();
1746 d_fprintf(stderr, "net ads dns register\n");
1750 if (!(ctx = talloc_init("net_ads_dns"))) {
1751 d_fprintf(stderr, "Could not initialise talloc context\n");
1755 status = ads_startup(True, &ads);
1756 if ( !ADS_ERR_OK(status) ) {
1757 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1762 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1763 d_fprintf( stderr, "DNS update failed!\n" );
1764 ads_destroy( &ads );
1769 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1776 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1781 #if defined(WITH_DNS_UPDATES)
1782 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1785 static int net_ads_dns_gethostbyname(int argc, const char **argv)
1787 #if defined(WITH_DNS_UPDATES)
1791 talloc_enable_leak_report();
1795 d_fprintf(stderr, "net ads dns gethostbyname <server> "
1800 err = do_gethostbyname(argv[0], argv[1]);
1802 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1807 static int net_ads_dns(int argc, const char *argv[])
1809 struct functable func[] = {
1810 {"REGISTER", net_ads_dns_register},
1811 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
1815 return net_run_function(argc, argv, func, net_ads_dns_usage);
1818 /*******************************************************************
1819 ********************************************************************/
1821 int net_ads_printer_usage(int argc, const char **argv)
1824 "\nnet ads printer search <printer>"
1825 "\n\tsearch for a printer in the directory\n"
1826 "\nnet ads printer info <printer> <server>"
1827 "\n\tlookup info in directory for printer on server"
1828 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1829 "\nnet ads printer publish <printername>"
1830 "\n\tpublish printer in directory"
1831 "\n\t(note: printer name is required)\n"
1832 "\nnet ads printer remove <printername>"
1833 "\n\tremove printer from directory"
1834 "\n\t(note: printer name is required)\n");
1838 /*******************************************************************
1839 ********************************************************************/
1841 static int net_ads_printer_search(int argc, const char **argv)
1845 LDAPMessage *res = NULL;
1847 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1851 rc = ads_find_printers(ads, &res);
1853 if (!ADS_ERR_OK(rc)) {
1854 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1855 ads_msgfree(ads, res);
1860 if (ads_count_replies(ads, res) == 0) {
1861 d_fprintf(stderr, "No results found\n");
1862 ads_msgfree(ads, res);
1868 ads_msgfree(ads, res);
1873 static int net_ads_printer_info(int argc, const char **argv)
1877 const char *servername, *printername;
1878 LDAPMessage *res = NULL;
1880 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
1885 printername = argv[0];
1891 servername = argv[1];
1893 servername = global_myname();
1896 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1898 if (!ADS_ERR_OK(rc)) {
1899 d_fprintf(stderr, "Server '%s' not found: %s\n",
1900 servername, ads_errstr(rc));
1901 ads_msgfree(ads, res);
1906 if (ads_count_replies(ads, res) == 0) {
1907 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1908 ads_msgfree(ads, res);
1914 ads_msgfree(ads, res);
1920 static int net_ads_printer_publish(int argc, const char **argv)
1924 const char *servername, *printername;
1925 struct cli_state *cli;
1926 struct rpc_pipe_client *pipe_hnd;
1927 struct in_addr server_ip;
1929 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1930 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1931 char *prt_dn, *srv_dn, **srv_cn;
1932 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1933 LDAPMessage *res = NULL;
1935 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
1936 talloc_destroy(mem_ctx);
1941 talloc_destroy(mem_ctx);
1942 return net_ads_printer_usage(argc, argv);
1945 printername = argv[0];
1948 servername = argv[1];
1950 servername = global_myname();
1953 /* Get printer data from SPOOLSS */
1955 resolve_name(servername, &server_ip, 0x20);
1957 nt_status = cli_full_connection(&cli, global_myname(), servername,
1960 opt_user_name, opt_workgroup,
1961 opt_password ? opt_password : "",
1962 CLI_FULL_CONNECTION_USE_KERBEROS,
1965 if (NT_STATUS_IS_ERR(nt_status)) {
1966 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1967 "for %s\n", servername, printername);
1969 talloc_destroy(mem_ctx);
1973 /* Publish on AD server */
1975 ads_find_machine_acct(ads, &res, servername);
1977 if (ads_count_replies(ads, res) == 0) {
1978 d_fprintf(stderr, "Could not find machine account for server %s\n",
1981 talloc_destroy(mem_ctx);
1985 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1986 srv_cn = ldap_explode_dn(srv_dn, 1);
1988 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1989 printername_escaped = escape_rdn_val_string_alloc(printername);
1990 if (!srv_cn_escaped || !printername_escaped) {
1991 SAFE_FREE(srv_cn_escaped);
1992 SAFE_FREE(printername_escaped);
1993 d_fprintf(stderr, "Internal error, out of memory!");
1995 talloc_destroy(mem_ctx);
1999 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
2001 SAFE_FREE(srv_cn_escaped);
2002 SAFE_FREE(printername_escaped);
2004 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
2006 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
2010 talloc_destroy(mem_ctx);
2014 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
2018 talloc_destroy(mem_ctx);
2022 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
2023 if (!ADS_ERR_OK(rc)) {
2024 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
2027 talloc_destroy(mem_ctx);
2031 d_printf("published printer\n");
2034 talloc_destroy(mem_ctx);
2039 static int net_ads_printer_remove(int argc, const char **argv)
2043 const char *servername;
2045 LDAPMessage *res = NULL;
2047 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2052 return net_ads_printer_usage(argc, argv);
2056 servername = argv[1];
2058 servername = global_myname();
2061 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2063 if (!ADS_ERR_OK(rc)) {
2064 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
2065 ads_msgfree(ads, res);
2070 if (ads_count_replies(ads, res) == 0) {
2071 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
2072 ads_msgfree(ads, res);
2077 prt_dn = ads_get_dn(ads, res);
2078 ads_msgfree(ads, res);
2079 rc = ads_del_dn(ads, prt_dn);
2080 ads_memfree(ads, prt_dn);
2082 if (!ADS_ERR_OK(rc)) {
2083 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
2092 static int net_ads_printer(int argc, const char **argv)
2094 struct functable func[] = {
2095 {"SEARCH", net_ads_printer_search},
2096 {"INFO", net_ads_printer_info},
2097 {"PUBLISH", net_ads_printer_publish},
2098 {"REMOVE", net_ads_printer_remove},
2102 return net_run_function(argc, argv, func, net_ads_printer_usage);
2106 static int net_ads_password(int argc, const char **argv)
2109 const char *auth_principal = opt_user_name;
2110 const char *auth_password = opt_password;
2112 char *new_password = NULL;
2117 if (opt_user_name == NULL || opt_password == NULL) {
2118 d_fprintf(stderr, "You must supply an administrator username/password\n");
2123 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
2128 if (!strchr_m(user, '@')) {
2129 asprintf(&c, "%s@%s", argv[0], lp_realm());
2133 use_in_memory_ccache();
2134 c = strchr_m(auth_principal, '@');
2141 /* use the realm so we can eventually change passwords for users
2142 in realms other than default */
2143 if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
2147 /* we don't actually need a full connect, but it's the easy way to
2148 fill in the KDC's addresss */
2151 if (!ads || !ads->config.realm) {
2152 d_fprintf(stderr, "Didn't find the kerberos server!\n");
2157 new_password = (char *)argv[1];
2159 asprintf(&prompt, "Enter new password for %s:", user);
2160 new_password = getpass(prompt);
2164 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2165 auth_password, user, new_password, ads->auth.time_offset);
2166 if (!ADS_ERR_OK(ret)) {
2167 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
2172 d_printf("Password change for %s completed.\n", user);
2178 int net_ads_changetrustpw(int argc, const char **argv)
2181 char *host_principal;
2185 if (!secrets_init()) {
2186 DEBUG(1,("Failed to initialise secrets database\n"));
2190 net_use_krb_machine_account();
2192 use_in_memory_ccache();
2194 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2198 fstrcpy(my_name, global_myname());
2199 strlower_m(my_name);
2200 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
2201 d_printf("Changing password for principal: %s\n", host_principal);
2203 ret = ads_change_trust_account_password(ads, host_principal);
2205 if (!ADS_ERR_OK(ret)) {
2206 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
2208 SAFE_FREE(host_principal);
2212 d_printf("Password change for principal %s succeeded.\n", host_principal);
2214 if (lp_use_kerberos_keytab()) {
2215 d_printf("Attempting to update system keytab with new password.\n");
2216 if (ads_keytab_create_default(ads)) {
2217 d_printf("Failed to update system keytab.\n");
2222 SAFE_FREE(host_principal);
2228 help for net ads search
2230 static int net_ads_search_usage(int argc, const char **argv)
2233 "\nnet ads search <expression> <attributes...>\n"\
2234 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2235 "The expression is a standard LDAP search expression, and the\n"\
2236 "attributes are a list of LDAP fields to show in the results\n\n"\
2237 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2239 net_common_flags_usage(argc, argv);
2245 general ADS search function. Useful in diagnosing problems in ADS
2247 static int net_ads_search(int argc, const char **argv)
2251 const char *ldap_exp;
2253 LDAPMessage *res = NULL;
2256 return net_ads_search_usage(argc, argv);
2259 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2266 rc = ads_do_search_all(ads, ads->config.bind_path,
2268 ldap_exp, attrs, &res);
2269 if (!ADS_ERR_OK(rc)) {
2270 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2275 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2277 /* dump the results */
2280 ads_msgfree(ads, res);
2288 help for net ads search
2290 static int net_ads_dn_usage(int argc, const char **argv)
2293 "\nnet ads dn <dn> <attributes...>\n"\
2294 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2295 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
2296 "to show in the results\n\n"\
2297 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2298 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2300 net_common_flags_usage(argc, argv);
2306 general ADS search function. Useful in diagnosing problems in ADS
2308 static int net_ads_dn(int argc, const char **argv)
2314 LDAPMessage *res = NULL;
2317 return net_ads_dn_usage(argc, argv);
2320 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2327 rc = ads_do_search_all(ads, dn,
2329 "(objectclass=*)", attrs, &res);
2330 if (!ADS_ERR_OK(rc)) {
2331 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2336 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2338 /* dump the results */
2341 ads_msgfree(ads, res);
2348 help for net ads sid search
2350 static int net_ads_sid_usage(int argc, const char **argv)
2353 "\nnet ads sid <sid> <attributes...>\n"\
2354 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
2355 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
2356 "to show in the results\n\n"\
2357 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2359 net_common_flags_usage(argc, argv);
2365 general ADS search function. Useful in diagnosing problems in ADS
2367 static int net_ads_sid(int argc, const char **argv)
2371 const char *sid_string;
2373 LDAPMessage *res = NULL;
2377 return net_ads_sid_usage(argc, argv);
2380 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
2384 sid_string = argv[0];
2387 if (!string_to_sid(&sid, sid_string)) {
2388 d_fprintf(stderr, "could not convert sid\n");
2393 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2394 if (!ADS_ERR_OK(rc)) {
2395 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2400 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2402 /* dump the results */
2405 ads_msgfree(ads, res);
2412 static int net_ads_keytab_usage(int argc, const char **argv)
2415 "net ads keytab <COMMAND>\n"\
2416 "<COMMAND> can be either:\n"\
2417 " ADD Adds new service principal\n"\
2418 " CREATE Creates a fresh keytab\n"\
2419 " FLUSH Flushes out all keytab entries\n"\
2420 " HELP Prints this help message\n"\
2421 " LIST List the keytab\n"\
2422 "The ADD and LIST command will take arguments, the other commands\n"\
2423 "will not take any arguments. The arguments given to ADD\n"\
2424 "should be a list of principals to add. For example, \n"\
2425 " net ads keytab add srv1 srv2\n"\
2426 "will add principals for the services srv1 and srv2 to the\n"\
2427 "system's keytab.\n"\
2428 "The LIST command takes a keytabname.\n"\
2434 static int net_ads_keytab_flush(int argc, const char **argv)
2439 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2442 ret = ads_keytab_flush(ads);
2447 static int net_ads_keytab_add(int argc, const char **argv)
2453 d_printf("Processing principals to add...\n");
2454 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2457 for (i = 0; i < argc; i++) {
2458 ret |= ads_keytab_add_entry(ads, argv[i]);
2464 static int net_ads_keytab_create(int argc, const char **argv)
2469 if (!ADS_ERR_OK(ads_startup(True, &ads))) {
2472 ret = ads_keytab_create_default(ads);
2477 static int net_ads_keytab_list(int argc, const char **argv)
2479 const char *keytab = NULL;
2485 return ads_keytab_list(keytab);
2489 int net_ads_keytab(int argc, const char **argv)
2491 struct functable func[] = {
2492 {"ADD", net_ads_keytab_add},
2493 {"CREATE", net_ads_keytab_create},
2494 {"FLUSH", net_ads_keytab_flush},
2495 {"HELP", net_ads_keytab_usage},
2496 {"LIST", net_ads_keytab_list},
2500 if (!lp_use_kerberos_keytab()) {
2501 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2502 use keytab functions.\n");
2505 return net_run_function(argc, argv, func, net_ads_keytab_usage);
2508 static int net_ads_kerberos_usage(int argc, const char **argv)
2511 "net ads kerberos <COMMAND>\n"\
2512 "<COMMAND> can be either:\n"\
2513 " RENEW Renew TGT from existing credential cache\n"\
2514 " PAC Dumps the Kerberos PAC\n"\
2515 " KINIT Retrieve Ticket Granting Ticket (TGT)\n"\
2522 static int net_ads_kerberos_renew(int argc, const char **argv)
2524 int ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2526 d_printf("failed to renew kerberos ticket: %s\n",
2527 error_message(ret));
2532 static int net_ads_kerberos_pac(int argc, const char **argv)
2534 PAC_DATA *pac = NULL;
2535 PAC_LOGON_INFO *info = NULL;
2536 TALLOC_CTX *mem_ctx = NULL;
2540 mem_ctx = talloc_init("net_ads_kerberos_pac");
2545 opt_password = net_prompt_pass(opt_user_name);
2547 status = kerberos_return_pac(mem_ctx,
2556 2592000, /* one month */
2558 if (!NT_STATUS_IS_OK(status)) {
2559 d_printf("failed to query kerberos PAC: %s\n",
2564 info = get_logon_info_from_pac(pac);
2566 dump_pac_logon_info(0, info);
2571 TALLOC_FREE(mem_ctx);
2575 static int net_ads_kerberos_kinit(int argc, const char **argv)
2577 TALLOC_CTX *mem_ctx = NULL;
2581 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2586 opt_password = net_prompt_pass(opt_user_name);
2588 ret = kerberos_kinit_password_ext(opt_user_name,
2596 2592000, /* one month */
2599 d_printf("failed to kinit password: %s\n",
2606 int net_ads_kerberos(int argc, const char **argv)
2608 struct functable func[] = {
2609 {"KINIT", net_ads_kerberos_kinit},
2610 {"RENEW", net_ads_kerberos_renew},
2611 {"PAC", net_ads_kerberos_pac},
2612 {"HELP", net_ads_kerberos_usage},
2616 return net_run_function(argc, argv, func, net_ads_kerberos_usage);
2620 int net_ads_help(int argc, const char **argv)
2622 struct functable func[] = {
2623 {"USER", net_ads_user_usage},
2624 {"GROUP", net_ads_group_usage},
2625 {"PRINTER", net_ads_printer_usage},
2626 {"SEARCH", net_ads_search_usage},
2627 {"INFO", net_ads_info},
2628 {"JOIN", net_ads_join_usage},
2629 {"DNS", net_ads_dns_usage},
2630 {"LEAVE", net_ads_leave},
2631 {"STATUS", net_ads_status},
2632 {"PASSWORD", net_ads_password},
2633 {"CHANGETRUSTPW", net_ads_changetrustpw},
2637 return net_run_function(argc, argv, func, net_ads_usage);
2640 int net_ads(int argc, const char **argv)
2642 struct functable func[] = {
2643 {"INFO", net_ads_info},
2644 {"JOIN", net_ads_join},
2645 {"TESTJOIN", net_ads_testjoin},
2646 {"LEAVE", net_ads_leave},
2647 {"STATUS", net_ads_status},
2648 {"USER", net_ads_user},
2649 {"GROUP", net_ads_group},
2650 {"DNS", net_ads_dns},
2651 {"PASSWORD", net_ads_password},
2652 {"CHANGETRUSTPW", net_ads_changetrustpw},
2653 {"PRINTER", net_ads_printer},
2654 {"SEARCH", net_ads_search},
2656 {"SID", net_ads_sid},
2657 {"WORKGROUP", net_ads_workgroup},
2658 {"LOOKUP", net_ads_lookup},
2659 {"KEYTAB", net_ads_keytab},
2660 {"GPO", net_ads_gpo},
2661 {"KERBEROS", net_ads_kerberos},
2662 {"HELP", net_ads_help},
2666 return net_run_function(argc, argv, func, net_ads_usage);
2671 static int net_ads_noads(void)
2673 d_fprintf(stderr, "ADS support not compiled in\n");
2677 int net_ads_keytab(int argc, const char **argv)
2679 return net_ads_noads();
2682 int net_ads_kerberos(int argc, const char **argv)
2684 return net_ads_noads();
2687 int net_ads_usage(int argc, const char **argv)
2689 return net_ads_noads();
2692 int net_ads_help(int argc, const char **argv)
2694 return net_ads_noads();
2697 int net_ads_changetrustpw(int argc, const char **argv)
2699 return net_ads_noads();
2702 int net_ads_join(int argc, const char **argv)
2704 return net_ads_noads();
2707 int net_ads_user(int argc, const char **argv)
2709 return net_ads_noads();
2712 int net_ads_group(int argc, const char **argv)
2714 return net_ads_noads();
2717 /* this one shouldn't display a message */
2718 int net_ads_check(void)
2723 int net_ads_check_our_domain(void)
2728 int net_ads(int argc, const char **argv)
2730 return net_ads_usage(argc, argv);
2733 #endif /* WITH_ADS */