domain trusts patch - corrected version

Rafal Szczesniak mimir at diament.ists.pwr.wroc.pl
Tue Feb 26 16:06:09 GMT 2002


This is the patch that extends 'net' tool with ability of creating
trusting domain's account on remote rpc server (samba not included
yet, sorry) and ability of establishing trust to a trusted nt domain.

What's new:
 - functions adding account (rpc_trustdom_add and 
   rpc_trustdom_add_internals)
 - functions establishing trust (rpc_trustdom_establish, net_find_dc)
 - functions revoking the trust (rpc_trustdom_revoke)
 - interface for tdb to store trusted domain account password in
   secrets.tdb
 - cli_wks_query_info is now part of libsmb

What's changed:
 - both connect_to_ipc and connect_to_ipc_anonymous now modify passed
   cli_struct and return NTSTATUS code
 - fixes of some typos, mostly in comments


Is there any Team member who could make a look and possibly commit this
patch ? More code is under construction ...

As usual, feedbacks are welcome :-)


cheers,
+------------------------------------------------------------+
|Rafal 'Mimir' Szczesniak <mimir at diament.ists.pwr.wroc.pl>   |
|*BSD, GNU/Linux and Samba                                  /
|__________________________________________________________/

-------------- next part --------------
diff -Nur samba/source/Makefile.in head/source/Makefile.in
--- samba/source/Makefile.in	Fri Feb 22 23:14:34 2002
+++ head/source/Makefile.in	Sun Feb 24 17:45:46 2002
@@ -155,8 +155,8 @@
 	     $(LIBADS_OBJ)
 
 LIBMSRPC_OBJ = libsmb/cli_lsarpc.o libsmb/cli_samr.o libsmb/cli_spoolss.o \
-	       libsmb/cli_netlogon.o libsmb/cli_srvsvc.o libsmb/cli_dfs.o \
-	       libsmb/cli_reg.o libsmb/trust_passwd.o\
+	       libsmb/cli_netlogon.o libsmb/cli_srvsvc.o libsmb/cli_wkssvc.o \
+	       libsmb/cli_dfs.o libsmb/cli_reg.o libsmb/trust_passwd.o\
 	       rpc_client/cli_pipe.o libsmb/cli_pipe_util.o
 
 LIBMSRPC_PICOBJ = $(LIBMSRPC_OBJ:.o=.po)
diff -Nur samba/source/auth/auth_util.c head/source/auth/auth_util.c
--- samba/source/auth/auth_util.c	Wed Jan 30 07:08:13 2002
+++ head/source/auth/auth_util.c	Thu Jan 31 01:42:26 2002
@@ -123,7 +123,7 @@
 
 	ZERO_STRUCTP(*user_info);
 
-	DEBUG(5,("makeing strings for %s's user_info struct\n", internal_username));
+	DEBUG(5,("making strings for %s's user_info struct\n", internal_username));
 
 	(*user_info)->smb_name.str = strdup(smb_name);
 	if ((*user_info)->smb_name.str) { 

diff -Nur samba/source/include/includes.h head/source/include/includes.h
--- samba/source/include/includes.h	Wed Jan 30 07:08:14 2002
+++ head/source/include/includes.h	Wed Feb 13 02:05:57 2002
@@ -699,7 +699,6 @@
 #include "hash.h"
 #include "trans2.h"
 #include "nterr.h"
-#include "secrets.h"
 #include "messages.h"
 #include "util_list.h"
 #include "charset.h"
@@ -717,5 +716,7 @@
 #include "smb.h"
 #include "smbw.h"
 #include "nameserv.h"
+
+#include "secrets.h"
 
 #include "byteorder.h"

diff -Nur samba/source/include/secrets.h head/source/include/secrets.h
--- samba/source/include/secrets.h	Wed Jan 30 07:08:15 2002
+++ head/source/include/secrets.h	Wed Feb 13 01:56:30 2002
@@ -22,18 +22,31 @@
 #define _SECRETS_H
 
 /* the first one is for the hashed password (NT4 style) the latter
-   for plaintext (ADS 
+   for plaintext (ADS)
 */
 #define SECRETS_MACHINE_ACCT_PASS "SECRETS/$MACHINE.ACC"
 #define SECRETS_MACHINE_PASSWORD "SECRETS/MACHINE_PASSWORD"
 
+/* this one is for storing trusted domain account password */
+#define SECRETS_DOMTRUST_ACCT_PASS "SECRETS/$DOMTRUST.ACC"
+
 
 #define SECRETS_DOMAIN_SID    "SECRETS/SID"
 #define SECRETS_SAM_SID       "SAM/SID"
 
+/* structure for storing machine account password
+   (ie. when samba server is member of a domain */
 struct machine_acct_pass {
 	uint8 hash[16];
 	time_t mod_time;
 };
+
+/* structure for storing trusted domain password */
+struct trusted_dom_pass {
+	uint8 hash[16];
+	time_t mod_time;
+	DOM_SID domain_sid; /* remote domain's sid */
+};
+
 
 #endif /* _SECRETS_H */

diff -Nur samba/source/libsmb/cli_wkssvc.c head/source/libsmb/cli_wkssvc.c
--- samba/source/libsmb/cli_wkssvc.c	Thu Jan  1 01:00:00 1970
+++ head/source/libsmb/cli_wkssvc.c	Sun Feb 24 18:11:04 2002
@@ -0,0 +1,112 @@
+/* 
+   Unix SMB/CIFS implementation.
+   NT Domain Authentication SMB / MSRPC client
+   Copyright (C) Andrew Tridgell 1994-2000
+   Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+   Copyright (C) Tim Potter 2001
+   Copytight (C) Rafal Szczesniak 2002
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/**
+ * Opens a SMB connection to the wkssvc pipe
+ *
+ * @param cli client structure (not yet initialised)
+ * @param system_name called rpc server name
+ * @param creds user credentials
+ *
+ * @return client structure with opened pipe
+ **/
+
+struct cli_state *cli_wkssvc_initialise(struct cli_state *cli, 
+					char *system_name,
+					struct ntuser_creds *creds)
+{
+        return cli_pipe_initialise(cli, system_name, PIPE_WKSSVC, creds);
+}
+
+
+/**
+ * WksQueryInfo rpc call (like query for server's capabilities)
+ *
+ * @param initialised client structure with \PIPE\wkssvc opened
+ * @param mem_ctx memory context assigned to this rpc binding
+ * @param wks100 WksQueryInfo structure
+ *
+ * @return NTSTATUS of rpc call
+ */
+ 
+NTSTATUS cli_wks_query_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+			    WKS_INFO_100 *wks100)
+{
+	prs_struct buf;
+	prs_struct rbuf;
+	WKS_Q_QUERY_INFO q_o;
+	WKS_R_QUERY_INFO r_o;
+	NTSTATUS nt_status;
+
+	if (cli == NULL || wks100 == NULL)
+		return NT_STATUS_UNSUCCESSFUL;
+
+	/* init rpc parse structures */
+	prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+	prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+	DEBUG(4, ("WksQueryInfo\n"));
+	
+	/* init query structure with rpc call arguments */
+	init_wks_q_query_info(&q_o, cli->desthost, 100);
+	
+	/* marshall data */
+	if (!wks_io_q_query_info("", &q_o, &buf, 0)) {
+		prs_mem_free(&buf);
+		prs_mem_free(&rbuf);
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+	
+	/* actual rpc call over \PIPE\wkssvc */
+	if (!rpc_api_pipe_req(cli, WKS_QUERY_INFO, &buf, &rbuf)) {
+		prs_mem_free(&buf);
+		prs_mem_free(&rbuf);
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+	
+	prs_mem_free(&buf);
+
+	r_o.wks100 = wks100;
+
+	/* get call results from response buffer */
+	if (!wks_io_r_query_info("", &r_o, &rbuf, 0)) {
+		prs_mem_free(&rbuf);
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+	
+	/* check returnet status code */
+	if (NT_STATUS_IS_ERR(r_o.status)) {
+		/* report the error */
+		DEBUG(0,("WKS_R_QUERY_INFO: %s\n", get_nt_error_msg(r_o.status)));
+		prs_mem_free(&rbuf);
+		return r_o.status;
+	}
+	
+	/* do clean up */
+	prs_mem_free(&rbuf);
+	
+	return nt_status;
+}
+

diff -Nur samba/source/libsmb/cliconnect.c head/source/libsmb/cliconnect.c
--- samba/source/libsmb/cliconnect.c	Wed Jan 30 07:08:18 2002
+++ head/source/libsmb/cliconnect.c	Sun Feb 24 16:47:45 2002
@@ -1270,6 +1270,15 @@
 	{
 		DEBUG(1,("failed session setup\n"));
 		nt_status = cli_nt_error(cli);
+
+		/* if it's a trusting domain's account pass the credentials anyway */
+		if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT)) {
+			init_creds(&creds, user, domain, password, pass_len);
+			cli_init_creds(cli, &creds);
+			*output_cli = cli;
+			return nt_status;
+		}
+		
 		cli_shutdown(cli);
 		if (NT_STATUS_IS_OK(nt_status)) nt_status = NT_STATUS_UNSUCCESSFUL;
 		return nt_status;
diff -Nur samba/source/libsmb/clientgen.c head/source/libsmb/clientgen.c
--- samba/source/libsmb/clientgen.c	Wed Jan 30 07:08:18 2002
+++ head/source/libsmb/clientgen.c	Mon Feb 11 01:01:31 2002
@@ -138,7 +138,7 @@
 
 
 /****************************************************************************
-initialise a client structure
+initialise credentials of a client structure
 ****************************************************************************/
 void cli_init_creds(struct cli_state *cli, const struct ntuser_creds *usr)
 {
diff -Nur samba/source/passdb/secrets.c head/source/passdb/secrets.c
--- samba/source/passdb/secrets.c	Fri Feb 22 23:15:15 2002
+++ head/source/passdb/secrets.c	Fri Feb 22 23:05:03 2002
@@ -136,7 +136,20 @@
 }
 
 /************************************************************************
- Routine to get the trust account password for a domain.
+form a key for fetching a trusted domain password
+************************************************************************/
+char *trustdom_keystr(char *domain)
+{
+	static fstring keystr;
+
+	slprintf(keystr,sizeof(keystr)-1,"%s/%s",
+		SECRETS_DOMTRUST_ACCT_PASS, domain);
+		
+	return keystr;
+}
+
+/************************************************************************
+ Routine to get the machine trust account password for a domain.
 ************************************************************************/
 BOOL secrets_fetch_trust_account_password(char *domain, uint8 ret_pwd[16],
 					  time_t *pass_last_set_time)
@@ -170,6 +183,32 @@
 	return True;
 }
 
+/************************************************************************
+ Routine to get account password to trusted domain
+************************************************************************/
+BOOL secrets_fetch_trusted_domain_password(char *domain, uint8 pwd[16],
+				DOM_SID sid, time_t *pass_last_set_time)
+{
+	struct trusted_dom_pass *pass;
+	size_t size;
+
+	if (!(pass = secrets_fetch(trustdom_keystr(domain), &size))) {
+		DEBUG(5, ("secrets_fetch failed!\n"));
+		return False;
+	}
+	
+	if (size != sizeof(*pass)) {
+		DEBUG(0, ("secrets were of incorrect size!\n"));
+		return False;
+	}
+	
+	if (pass_last_set_time) *pass_last_set_time = pass->mod_time;
+	memcpy(pwd, pass->hash, 16);
+	memcpy(&sid, &(pass->domain_sid), sizeof(sid));
+	SAFE_FREE(pass);
+	
+	return True;
+}
 
 /************************************************************************
  Routine to set the trust account password for a domain.
@@ -185,6 +224,21 @@
 }
 
 /************************************************************************
+ Routine to set the password for trusted domain
+************************************************************************/
+BOOL secrets_store_trusted_domain_password(char* domain, uint8 new_pwd[16],
+					   DOM_SID sid)
+{
+	struct trusted_dom_pass pass;
+
+	pass.mod_time = time(NULL);
+	memcpy(pass.hash, new_pwd, 16);
+	memcpy(&(pass.domain_sid), &sid, sizeof(sid));
+	
+	return secrets_store(trustdom_keystr(domain), (void *)&pass, sizeof(pass));
+}
+
+/************************************************************************
  Routine to set the plaintext machine account password for a realm
 the password is assumed to be a null terminated ascii string
 ************************************************************************/
@@ -218,13 +272,22 @@
 
 
 /************************************************************************
- Routine to delete the trust account password file for a domain.
+ Routine to delete the machine trust account password file for a domain.
 ************************************************************************/
 
 BOOL trust_password_delete(char *domain)
 {
 	return secrets_delete(trust_keystr(domain));
 }
+
+/************************************************************************
+ Routine to delete the password for trusted domain
+************************************************************************/
+BOOL trusted_domain_password_delete(char *domain)
+{
+	return secrets_delete(trustdom_keystr(domain));
+}
+
 
 /*******************************************************************
  Reset the 'done' variables so after a client process is created

diff -Nur samba/source/smbd/process.c head/source/smbd/process.c
--- samba/source/smbd/process.c	Fri Feb  1 00:26:11 2002
+++ head/source/smbd/process.c	Fri Feb  1 01:05:08 2002
@@ -818,7 +818,7 @@
 }
 
 /****************************************************************************
-  process an smb from the client - split out from the process() code so
+  process an smb from the client - split out from the smbd_process() code so
   it can be used by the oplock break code.
 ****************************************************************************/
 void process_smb(char *inbuf, char *outbuf)

diff -Nur samba/source/tdb/tdb.c head/source/tdb/tdb.c
--- samba/source/tdb/tdb.c	Wed Jan 30 07:08:41 2002
+++ head/source/tdb/tdb.c	Mon Feb 25 22:14:55 2002
@@ -243,7 +243,7 @@
 	tdb->locked[list+1].count--;
 }
 
-/* This is based on the hash agorithm from gdbm */
+/* This is based on the hash algorithm from gdbm */
 static u32 tdb_hash(TDB_DATA *key)
 {
 	u32 value;	/* Used to compute the hash value.  */

diff -Nur samba/source/utils/net.c head/source/utils/net.c
--- samba/source/utils/net.c	Wed Jan 30 07:08:43 2002
+++ head/source/utils/net.c	Sun Feb 24 15:46:28 2002
@@ -104,9 +104,9 @@
 /****************************************************************************
 connect to \\server\ipc$  
 ****************************************************************************/
-static struct cli_state *connect_to_ipc(struct in_addr *server_ip, const char *server_name)
+NTSTATUS connect_to_ipc(struct cli_state **c, struct in_addr *server_ip,
+					const char *server_name)
 {
-	struct cli_state *c;
 	NTSTATUS nt_status;
 
 	if (!got_pass) {
@@ -116,14 +116,14 @@
 		}
 	}
 	
-	nt_status = cli_full_connection(&c, opt_requester_name, server_name, 
+	nt_status = cli_full_connection(c, opt_requester_name, server_name, 
 					server_ip, opt_port,
 					"IPC$", "IPC",  
 					opt_user_name, opt_workgroup,
 					opt_password, strlen(opt_password));
 	
 	if (NT_STATUS_IS_OK(nt_status)) {
-		return c;
+		return nt_status;
 	} else {
 		DEBUG(0,("Cannot connect to server.  Error was %s\n", 
 			 get_nt_error_msg(nt_status)));
@@ -134,29 +134,29 @@
 		    NT_STATUS_V(NT_STATUS_LOGON_FAILURE))
 			d_printf("The username or password was not correct.\n");
 
-		return NULL;
+		return nt_status;
 	}
 }
 
 /****************************************************************************
 connect to \\server\ipc$ anonymously
 ****************************************************************************/
-static struct cli_state *connect_to_ipc_anonymous(struct in_addr *server_ip, const char *server_name)
+NTSTATUS connect_to_ipc_anonymous(struct cli_state **c,
+			struct in_addr *server_ip, const char *server_name)
 {
-	struct cli_state *c;
 	NTSTATUS nt_status;
 
-	nt_status = cli_full_connection(&c, opt_requester_name, server_name, 
+	nt_status = cli_full_connection(c, opt_requester_name, server_name, 
 					server_ip, opt_port,
 					"IPC$", "IPC",  
 					"", "",
 					"", 0);
 	
 	if (NT_STATUS_IS_OK(nt_status)) {
-		return c;
+		return nt_status;
 	} else {
 		DEBUG(0,("Cannot connect to server (anonymously).  Error was %s\n", get_nt_error_msg(nt_status)));
-		return NULL;
+		return nt_status;
 	}
 }
 
@@ -232,11 +232,38 @@
 	return True;
 }
 
+
+BOOL net_find_dc(struct in_addr *server_ip, char *server_name, char *domain_name)
+{
+	struct in_addr *ip_list;
+	int addr_count;
+
+	if (get_dc_list(True /* PDC only*/, domain_name, &ip_list, &addr_count)) {
+		fstring dc_name;
+		if (addr_count < 1) {
+			return False;
+		}
+			
+		*server_ip = *ip_list;
+		
+		if (is_zero_ip(*server_ip))
+			return False;
+		
+		if (!lookup_dc_name(global_myname, domain_name, server_ip, dc_name))
+			return False;
+			
+		safe_strcpy(server_name, dc_name, FSTRING_LEN);
+		return True;
+	} else
+		return False;
+}
+
 struct cli_state *net_make_ipc_connection(unsigned flags)
 {
 	char *server_name = NULL;
 	struct in_addr server_ip;
-	struct cli_state *cli;
+	struct cli_state *cli = NULL;
+	NTSTATUS nt_status;
 
 	if (!net_find_server(flags, &server_ip, &server_name)) {
 		d_printf("\nUnable to find a suitable server\n");
@@ -244,9 +328,9 @@
 	}
 
 	if (flags & NET_FLAGS_ANONYMOUS) {
-		cli = connect_to_ipc_anonymous(&server_ip, server_name);
+		nt_status = connect_to_ipc_anonymous(cli, &server_ip, server_name);
 	} else {
-		cli = connect_to_ipc(&server_ip, server_name);
+		nt_status = connect_to_ipc(cli, &server_ip, server_name);
 	}
 	SAFE_FREE(server_name);
 	return cli;
@@ -265,13 +349,12 @@
 
 static int help_usage(int argc, const char **argv)
 {
-	d_printf(
-"\n"\
-"Usage: net help <function>\n"\
-"\n"\
-"Valid functions are:\n"\
-"  RPC RAP ADS FILE SHARE SESSION SERVER DOMAIN PRINTQ USER GROUP VALIDATE\n"\
-"  GROUPMEMBER ADMIN SERVICE PASSWORD TIME LOOKUP\n");
+	d_printf("\n");
+	d_printf("Usage: net help <function>\n");
+	d_printf("\n");
+	d_printf("Valid functions are:\n");
+	d_printf("  RPC RAP ADS FILE SHARE SESSION SERVER DOMAIN PRINTQ USER GROUP VALIDATE\n");
+	d_printf("  GROUPMEMBER ADMIN SERVICE PASSWORD TIME LOOKUP\n");
 	return -1;
 }
 
diff -Nur samba/source/utils/net.h head/source/utils/net.h
--- samba/source/utils/net.h	Wed Jan 30 07:08:45 2002
+++ head/source/utils/net.h	Sat Feb  9 16:25:32 2002
@@ -45,3 +45,4 @@
 extern int opt_reboot;
 extern int opt_force;
 extern int opt_timeout;
+
diff -Nur samba/source/utils/net_rpc.c head/source/utils/net_rpc.c
--- samba/source/utils/net_rpc.c	Wed Jan 30 07:08:45 2002
+++ head/source/utils/net_rpc.c	Tue Feb 26 17:44:18 2002
@@ -302,9 +302,9 @@
  * All paramaters are provided by the run_rpc_command funcion, except for
  * argc, argv which are passes through. 
  *
- * @param domain_sid The domain sid aquired from the remote server
+ * @param domain_sid The domain sid acquired from the remote server
  * @param cli A cli_state connected to the server.
- * @param mem_ctx Talloc context, destoyed on compleation of the function.
+ * @param mem_ctx Talloc context, destoyed on completion of the function.
  * @param argc  Standard main() style argc
  * @param argc  Standard main() style argv.  Initial components are already
  *              stripped
@@ -554,6 +554,373 @@
 				       argc, argv);
 }
 
+/***************************************************************************
+  NT Domain trusts code (i.e. 'net rpc trustdom' functionality)
+  
+ ***************************************************************************/
+
+/**
+ * Add interdomain trust account to the RPC server.
+ * All parameters (except for argc and argv) are passed by run_rpc_command
+ * function.
+ *
+ * @param domain_sid The domain sid acquired from the server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on completion of the function.
+ * @param argc  Standard main() style argc
+ * @param argc  Standard main() style argv.  Initial components are already
+ *              stripped
+ *
+ * @return normal NTSTATUS return code
+ */
+
+static NTSTATUS rpc_trustdom_add_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+				       int argc, const char **argv) {
+
+	POLICY_HND connect_pol, domain_pol, user_pol;
+	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+	fstring acct_name;
+	uint16 acb_info;
+	uint32 unknown, user_rid;
+
+	if (argc != 1) {
+		d_printf("Usage: net rpc trustdom add <domain_name>\n");
+		return NT_STATUS_OK;
+	}
+
+	/* 
+	 * Make valid trusting domain account (ie. uppercased and with '$' appended)
+	 */
+	 
+	snprintf(acct_name, sizeof(acct_name) - 1, "%s$", argv[0]);
+	strupper(acct_name);
+
+	/* Get sam policy handle */
+	
+	result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
+				  &connect_pol);
+	if (!NT_STATUS_IS_OK(result)) {
+		goto done;
+	}
+	
+	/* Get domain policy handle */
+	
+	result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+				      MAXIMUM_ALLOWED_ACCESS,
+				      domain_sid, &domain_pol);
+	if (!NT_STATUS_IS_OK(result)) {
+		goto done;
+	}
+
+	/* Create trusting domain's account */
+
+	acb_info = ACB_DOMTRUST;
+	unknown = 0xe005000b; /* No idea what this is - a permission mask? 
+				 Is it needed for interdomain account also ? */
+
+	result = cli_samr_create_dom_user(cli, mem_ctx, &domain_pol,
+					  acct_name, acb_info, unknown,
+					  &user_pol, &user_rid);
+	if (!NT_STATUS_IS_OK(result)) {
+		goto done;
+	}
+
+ done:
+	return result;
+}
+
+/**
+ * Create interdomain trust account for a remote domain.
+ *
+ * @param argc standard argc
+ * @param argv standard argv without initial components
+ *
+ * @return Integer status (0 means success)
+ **/
+
+static int rpc_trustdom_add(int argc, const char **argv)
+{
+	return run_rpc_command(PIPE_SAMR, 0, rpc_trustdom_add_internals,
+			       argc, argv);
+}
+
+
+/**
+ * Delete interdomain trust account for a remote domain.
+ *
+ * @param argc standard argc
+ * @param argv standard argv without initial components
+ *
+ * @return Integer status (0 means success)
+ **/
+ 
+static int rpc_trustdom_del(int argc, const char **argv)
+{
+	d_printf("Sorry, not yet implemented.\n");
+	return -1;
+}
+
+ 
+/**
+ * Establish trust relationship to a trusting domain.
+ * Interdomain account must already be created on remote PDC.
+ *
+ * @param argc standard argc
+ * @param argv standard argv without initial components
+ *
+ * @return Integer status (0 means success)
+ **/
+
+extern char *opt_user_name;
+
+static int rpc_trustdom_establish(int argc, const char **argv) {
+
+	struct cli_state *cli;
+	struct in_addr server_ip;
+	POLICY_HND connect_hnd;
+	TALLOC_CTX *mem_ctx;
+	NTSTATUS nt_status;
+	DOM_SID domain_sid;
+	WKS_INFO_100 wks_info;
+	
+	uchar ntpwd[16];
+	
+	fstring domain_name;
+	fstring acct_name;
+	fstring pdc_name;
+
+	/*
+	 * Connect to \\server\ipc$ as 'our domain' account with password
+	 */
+
+	safe_strcpy(domain_name, argv[0], FSTRING_LEN);
+	strupper(domain_name);
+	
+	snprintf(acct_name, strlen(lp_workgroup()) + 2, "%s$", lp_workgroup());
+	strupper(acct_name);
+	
+	opt_user_name = (char*)malloc(strlen(acct_name) + 1);
+	safe_strcpy(opt_user_name, acct_name, strlen(acct_name) + 1);
+
+	/* find the domain controller */
+	if (!net_find_dc(&server_ip, pdc_name, domain_name)) {
+		DEBUG(0, ("Coulnd find domain controller for domain %s\n", domain_name));
+		return -1;
+	}
+
+	/* connect to ipc$ as username/password */
+	nt_status = connect_to_ipc(&cli, &server_ip, pdc_name);
+	if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT)) {
+
+		/* Is it trusting domain account for sure ? */
+		DEBUG(0, ("Couldn't verify trusting domain account. Error was %s\n",
+			get_nt_error_msg(nt_status)));
+		return -1;
+	}
+	
+	/* copy account's nt password hash */
+	if (cli)
+		safe_strcpy(ntpwd, cli->pwd.smb_nt_pwd, 16);
+	else
+		return -1;
+	
+	/*
+	 * Connect to \\server\ipc$ again (this time anonymously)
+	 */
+	
+	nt_status = connect_to_ipc_anonymous(&cli, &server_ip, pdc_name);
+	
+	if (NT_STATUS_IS_ERR(nt_status)) {
+		DEBUG(0, ("Couldn't connect to domain %s controller. Error was %s.\n",
+			domain_name, get_nt_error_msg(nt_status)));
+	}
+
+	/*
+	 * Use NetServerEnum2 to make sure we're talking to a proper server
+	 */
+	 
+	if (!cli_get_pdc_name(cli, domain_name, pdc_name)) {
+		DEBUG(0, ("NetServerEnum2 error: Couldn't find primary domain controller\
+			 for domain %s\n", domain_name));
+	}
+	 
+	/*
+	 * Call WksQueryInfo to check remote server's capabilities
+	 * FIXME:Is really necessary ? nt serv does this, but from samba's
+	 *       point of view it doesn't seem to make the difference
+	 * IDEA: It may be used to get info about type of pdc we're talking to
+	 *       (e.g. WinNT or Win2k)
+	 */
+	
+	if (!cli_nt_session_open(cli, PIPE_WKSSVC)) {
+		DEBUG(0, ("Couldn't not initialise wkssvc pipe\n"));
+		return -1;
+	}
+
+	/* TODO: convert this call from rpc_client/cli_wkssvc.c
+	   to cli_wks_query_info() in libsmb/cli_wkssvc.c
+	   UPDATE: already done :)
+	*/
+   
+	if (!(mem_ctx = talloc_init())) {
+		DEBUG(0, ("talloc_init() failed\n"));
+		cli_shutdown(cli);
+		return -1;
+	}
+	
+   	nt_status = cli_wks_query_info(cli, mem_ctx, &wks_info);
+	
+	if (NT_STATUS_IS_ERR(nt_status)) {
+		DEBUG(0, ("WksQueryInfo call failed.\n"));
+		return -1;
+	}
+
+	if (cli->nt_pipe_fnum) {
+		cli_nt_session_close(cli);
+		talloc_destroy(mem_ctx);
+	}
+
+
+	/*
+	 * Call LsaOpenPolicy and LsaQueryInfo
+	 */
+	 
+	if (!(mem_ctx = talloc_init())) {
+		DEBUG(0, ("talloc_init() failed\n"));
+		cli_shutdown(cli);
+		return -1;
+	}
+
+	if (!cli_nt_session_open(cli, PIPE_LSARPC)) {
+		DEBUG(0, ("Could not initialise lsa pipe\n"));
+	}
+
+	nt_status = cli_lsa_open_policy2(cli, mem_ctx, True, SEC_RIGHTS_QUERY_VALUE,
+					&connect_hnd);
+	if (NT_STATUS_IS_ERR(nt_status)) {
+		DEBUG(0, ("Couldn't open policy handle. Error was %s\n",
+			get_nt_error_msg(nt_status)));
+		return -1;
+	}
+
+	/* Querying info level 5 */
+			
+	nt_status = cli_lsa_query_info_policy(cli, mem_ctx, &connect_hnd,
+					5 /* info level */, domain_name, &domain_sid);
+	if (NT_STATUS_IS_ERR(nt_status)) {
+		DEBUG(0, ("LSA Query Info failed. Returned error was %s\n",
+			get_nt_error_msg(nt_status)));
+		return -1;
+	}
+
+
+	/* There should be actually query info level 3 (following nt serv behaviour),
+	   but I still don't know if it's _really_ necessary */
+			
+	/*
+	 * Close the pipes and clean up
+	 */
+	 
+	nt_status = cli_lsa_close(cli, mem_ctx, &connect_hnd);
+	if (NT_STATUS_IS_ERR(nt_status)) {
+		DEBUG(0, ("Couldn't close LSA pipe. Error was %s\n",
+			get_nt_error_msg(nt_status)));
+		return -1;
+	}
+
+	if (cli->nt_pipe_fnum)
+		cli_nt_session_close(cli);
+
+	talloc_destroy(mem_ctx);
+	 
+	 
+	/*
+	 * Store the password in secrets db
+	 */
+
+	if (!secrets_store_trusted_domain_password(domain_name, ntpwd, domain_sid)) {
+		DEBUG(0, ("Storing password for trusted domain failed.\n"));
+		return -1;
+	}
+	
+	return 0;
+}
+
+/**
+ * Revoke trust relationship to the remote domain
+ *
+ * @param argc standard argc
+ * @param argv standard argv without initial components
+ *
+ * @return Integer status (0 means success)
+ **/
+
+static int rpc_trustdom_revoke(int argc, const char **argv) {
+
+	fstring domain_name;
+
+	if (argc < 1) return -1;
+	
+	/* generate upper cased domain name */
+	safe_strcpy(domain_name, argv[0], FSTRING_LEN);
+	strupper(domain_name);
+
+	/* delete password of the trust */
+	if (!trusted_domain_password_delete(domain_name)) {
+		DEBUG(0, ("Failed to revoke relationship to the trusted domain %s\n",
+			  domain_name));
+		return -1;
+	};
+	
+	return 0;
+}
+
+/**
+ * Usage for 'net rpc trustdom' command
+ *
+ * @param argc standard argc
+ * @param argv standard argv without inital components
+ *
+ * @return Integer status returned to shell
+ **/
+ 
+static int rpc_trustdom_usage(int argc, const char **argv) {
+	d_printf("  net rpc trustdom add \t\t add trusting domain's account\n");
+	d_printf("  net rpc trustdom del \t\t delete trusting domain's account\n");
+	d_printf("  net rpc trustdom establish \t establish relationship to trusted domain\n");
+	d_printf("  net rpc trustdom revoke \t abandon relationship to trusted domain\n");
+	d_printf("  net rpc trustdom list \t show current interdomain trust relationships\n");
+	return -1;
+}
+
+
+/**
+ * Entrypoint for 'net rpc trustdom' code
+ *
+ * @param argc standard argc
+ * @param argv standard argv without initial components
+ *
+ * @return Integer status (0 means success)
+ */
+
+static int rpc_trustdom(int argc, const char **argv)
+{
+	struct functable func[] = {
+		{"add", rpc_trustdom_add},
+		{"del", rpc_trustdom_del},
+		{"establish", rpc_trustdom_establish},
+		{"revoke", rpc_trustdom_revoke},
+		{NULL, NULL}
+	};
+
+	if (argc == 0) {
+		rpc_trustdom_usage(argc, argv);
+		return -1;
+	}
+
+	return (net_run_function(argc, argv, func, rpc_user_usage));
+}
+
 /****************************************************************************/
 
 
@@ -569,6 +936,7 @@
 	d_printf("  net rpc join \tto join a domain \n");
 	d_printf("  net rpc user \tto add, delete and list users\n");
 	d_printf("  net rpc changetrustpw \tto change the trust account password\n");
+	d_printf("  net rpc trustdom \tto create trusting domain's account or establish trust\n");
 	d_printf("  net rpc abortshutdown \tto to abort the shutdown of a remote server\n");
 	d_printf("  net rpc shutdown \tto to shutdown a remote server\n");
 	d_printf("\n");
@@ -593,6 +961,7 @@
 		{"join", rpc_join},
 		{"user", rpc_user},
 		{"changetrustpw", rpc_changetrustpw},
+		{"trustdom", rpc_trustdom},
 		{"abortshutdown", rpc_shutdown_abort},
 		{"shutdown", rpc_shutdown},
 		{NULL, NULL}


More information about the samba-technical mailing list