summaryrefslogtreecommitdiffstats
path: root/source/rpc_client
diff options
context:
space:
mode:
Diffstat (limited to 'source/rpc_client')
-rw-r--r--source/rpc_client/cli_login.c174
-rw-r--r--source/rpc_client/cli_netlogon.c471
-rw-r--r--source/rpc_client/cli_pipe.c1260
-rw-r--r--source/rpc_client/cli_reg.c1072
-rw-r--r--source/rpc_client/cli_samr.c838
-rw-r--r--source/rpc_client/cli_spoolss.c818
-rw-r--r--source/rpc_client/cli_spoolss_notify.c293
-rw-r--r--source/rpc_client/cli_srvsvc.c401
-rw-r--r--source/rpc_client/cli_trust.c152
-rw-r--r--source/rpc_client/cli_wkssvc.c85
-rw-r--r--source/rpc_client/msrpc_spoolss.c810
-rw-r--r--source/rpc_client/ntclienttrust.c158
12 files changed, 6532 insertions, 0 deletions
diff --git a/source/rpc_client/cli_login.c b/source/rpc_client/cli_login.c
new file mode 100644
index 00000000000..be32533541c
--- /dev/null
+++ b/source/rpc_client/cli_login.c
@@ -0,0 +1,174 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Jeremy Allison 1999.
+
+ 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"
+
+extern fstring global_myworkgroup;
+extern pstring global_myname;
+
+/****************************************************************************
+Initialize domain session credentials.
+****************************************************************************/
+
+NTSTATUS cli_nt_setup_creds(struct cli_state *cli, unsigned char mach_pwd[16])
+{
+ NTSTATUS result;
+ DOM_CHAL clnt_chal;
+ DOM_CHAL srv_chal;
+
+ UTIME zerotime;
+
+ /******************* Request Challenge ********************/
+
+ generate_random_buffer( clnt_chal.data, 8, False);
+
+ /* send a client challenge; receive a server challenge */
+ if (!cli_net_req_chal(cli, &clnt_chal, &srv_chal))
+ {
+ DEBUG(0,("cli_nt_setup_creds: request challenge failed\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /**************** Long-term Session key **************/
+
+ /* calculate the session key */
+ cred_session_key(&clnt_chal, &srv_chal, (char *)mach_pwd, cli->sess_key);
+ memset((char *)cli->sess_key+8, '\0', 8);
+
+ /******************* Authenticate 2 ********************/
+
+ /* calculate auth-2 credentials */
+ zerotime.time = 0;
+ cred_create(cli->sess_key, &clnt_chal, zerotime, &(cli->clnt_cred.challenge));
+
+ /*
+ * Send client auth-2 challenge.
+ * Receive an auth-2 challenge response and check it.
+ */
+
+ result = cli_net_auth2(cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
+ SEC_CHAN_WKSTA : SEC_CHAN_BDC, 0x000001ff, &srv_chal);
+
+ if (!NT_STATUS_IS_OK(result))
+ {
+ DEBUG(0,("cli_nt_setup_creds: auth2 challenge failed\n"));
+ return result;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+NT login - interactive.
+*NEVER* use this code. This method of doing a logon (sending the cleartext
+password equivalents, protected by the session key) is inherently insecure
+given the current design of the NT Domain system. JRA.
+ ****************************************************************************/
+NTSTATUS cli_nt_login_interactive(struct cli_state *cli, char *domain, char *username,
+ uint32 smb_userid_low, char *password,
+ NET_ID_INFO_CTR *ctr, NET_USER_INFO_3 *user_info3)
+{
+ uchar lm_owf_user_pwd[16];
+ uchar nt_owf_user_pwd[16];
+ NTSTATUS ret;
+
+ DEBUG(5,("cli_nt_login_interactive: %d\n", __LINE__));
+
+ nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
+
+#ifdef DEBUG_PASSWORD
+
+ DEBUG(100,("nt owf of user password: "));
+ dump_data(100, (char *)lm_owf_user_pwd, 16);
+
+ DEBUG(100,("nt owf of user password: "));
+ dump_data(100, (char *)nt_owf_user_pwd, 16);
+
+#endif
+
+ DEBUG(5,("cli_nt_login_interactive: %d\n", __LINE__));
+
+ /* indicate an "interactive" login */
+ ctr->switch_value = INTERACTIVE_LOGON_TYPE;
+
+ /* Create the structure needed for SAM logon. */
+ init_id_info1(&ctr->auth.id1, domain, 0,
+ smb_userid_low, 0,
+ username, cli->clnt_name_slash,
+ (char *)cli->sess_key, lm_owf_user_pwd, nt_owf_user_pwd);
+
+ /* Ensure we overwrite all the plaintext password
+ equivalents. */
+ memset(lm_owf_user_pwd, '\0', sizeof(lm_owf_user_pwd));
+ memset(nt_owf_user_pwd, '\0', sizeof(nt_owf_user_pwd));
+
+ /* Send client sam-logon request - update credentials on success. */
+ ret = cli_net_sam_logon(cli, ctr, user_info3);
+
+ memset(ctr->auth.id1.lm_owf.data, '\0', sizeof(lm_owf_user_pwd));
+ memset(ctr->auth.id1.nt_owf.data, '\0', sizeof(nt_owf_user_pwd));
+
+ return ret;
+}
+
+/****************************************************************************
+NT login - network.
+*ALWAYS* use this call to validate a user as it does not expose plaintext
+password equivalents over the network. JRA.
+****************************************************************************/
+
+NTSTATUS cli_nt_login_network(struct cli_state *cli,
+ const auth_usersupplied_info *user_info,
+ uchar chal[8],
+ uint32 smb_userid_low, NET_ID_INFO_CTR *ctr,
+ NET_USER_INFO_3 *user_info3)
+{
+ DEBUG(5,("cli_nt_login_network: %d\n", __LINE__));
+ /* indicate a "network" login */
+ ctr->switch_value = NET_LOGON_TYPE;
+
+ /* Create the structure needed for SAM logon. */
+ init_id_info2(&ctr->auth.id2, user_info->domain.str, 0, smb_userid_low, 0,
+ user_info->smb_name.str,
+ /* Send our cleint's workstaion name if we have it, otherwise ours */
+ ((user_info->wksta_name.len > 0) ?
+ user_info->wksta_name.str :
+ cli->clnt_name_slash),
+ chal,
+ user_info->lm_resp.data, user_info->lm_resp.length,
+ user_info->nt_resp.data, user_info->nt_resp.length);
+
+ /* Send client sam-logon request - update credentials on success. */
+ return cli_net_sam_logon(cli, ctr, user_info3);
+}
+
+/****************************************************************************
+NT Logoff.
+****************************************************************************/
+BOOL cli_nt_logoff(struct cli_state *cli, NET_ID_INFO_CTR *ctr)
+{
+ DEBUG(5,("cli_nt_logoff: %d\n", __LINE__));
+
+ /* Send client sam-logoff request - update credentials on success. */
+ return cli_net_sam_logoff(cli, ctr);
+}
diff --git a/source/rpc_client/cli_netlogon.c b/source/rpc_client/cli_netlogon.c
new file mode 100644
index 00000000000..8a2d8e28cc1
--- /dev/null
+++ b/source/rpc_client/cli_netlogon.c
@@ -0,0 +1,471 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1998.
+ *
+ * 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"
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+
+/****************************************************************************
+Generate the next creds to use.
+****************************************************************************/
+
+static void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred)
+{
+ /*
+ * Create the new client credentials.
+ */
+
+ cli->clnt_cred.timestamp.time = time(NULL);
+
+ memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred));
+
+ /* Calculate the new credentials. */
+ cred_create(cli->sess_key, &(cli->clnt_cred.challenge),
+ new_clnt_cred->timestamp, &(new_clnt_cred->challenge));
+
+}
+
+#if UNUSED_CODE
+/****************************************************************************
+do a LSA Logon Control2
+****************************************************************************/
+BOOL cli_net_logon_ctrl2(struct cli_state *cli, NTSTATUS status_level)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ NET_Q_LOGON_CTRL2 q_l;
+ BOOL ok = False;
+
+ prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_LOGON_CTRL2 */
+
+ DEBUG(4,("do_net_logon_ctrl2 from %s status level:%x\n",
+ global_myname, status_level));
+
+ /* store the parameters */
+ init_q_logon_ctrl2(&q_l, cli->srv_name_slash,
+ status_level);
+
+ /* turn parameters into data stream */
+ if(!net_io_q_logon_ctrl2("", &q_l, &buf, 0)) {
+ DEBUG(0,("cli_net_logon_ctrl2: Error : failed to marshall NET_Q_LOGON_CTRL2 struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_LOGON_CTRL2, &buf, &rbuf))
+ {
+ NET_R_LOGON_CTRL2 r_l;
+
+ /*
+ * Unmarshall the return buffer.
+ */
+ ok = net_io_r_logon_ctrl2("", &r_l, &rbuf, 0);
+
+ if (ok && r_l.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("do_net_logon_ctrl2: Error %s\n", get_nt_error_msg(r_l.status)));
+ cli->nt_error = r_l.status;
+ ok = False;
+ }
+ }
+
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+
+ return ok;
+}
+#endif
+
+/****************************************************************************
+LSA Authenticate 2
+
+Send the client credential, receive back a server credential.
+Ensure that the server credential returned matches the session key
+encrypt of the server challenge originally received. JRA.
+****************************************************************************/
+
+NTSTATUS cli_net_auth2(struct cli_state *cli, uint16 sec_chan,
+ uint32 neg_flags, DOM_CHAL *srv_chal)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ NET_Q_AUTH_2 q_a;
+ BOOL ok = False;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_AUTH2 */
+
+ DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname,
+ credstr(cli->clnt_cred.challenge.data), neg_flags));
+
+ /* store the parameters */
+ init_q_auth_2(&q_a, cli->srv_name_slash, cli->mach_acct,
+ sec_chan, global_myname, &cli->clnt_cred.challenge, neg_flags);
+
+ /* turn parameters into data stream */
+ if(!net_io_q_auth_2("", &q_a, &buf, 0)) {
+ DEBUG(0,("cli_net_auth2: Error : failed to marshall NET_Q_AUTH_2 struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return result;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_AUTH2, &buf, &rbuf))
+ {
+ NET_R_AUTH_2 r_a;
+
+ ok = net_io_r_auth_2("", &r_a, &rbuf, 0);
+ result = r_a.status;
+
+ if (ok && !NT_STATUS_IS_OK(result))
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_auth2: Error %s\n", get_nt_error_msg(result)));
+ ok = False;
+ }
+
+ if (ok)
+ {
+ /*
+ * Check the returned value using the initial
+ * server received challenge.
+ */
+ UTIME zerotime;
+
+ zerotime.time = 0;
+ if(cred_assert( &r_a.srv_chal, cli->sess_key, srv_chal, zerotime) == 0) {
+ /*
+ * Server replied with bad credential. Fail.
+ */
+ DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
+password ?).\n", cli->desthost ));
+ ok = False;
+ }
+ }
+
+#if 0
+ /*
+ * Try commenting this out to see if this makes the connect
+ * work for a NT 3.51 PDC. JRA.
+ */
+
+ if (ok && r_a.srv_flgs.neg_flags != q_a.clnt_flgs.neg_flags)
+ {
+ /* report different neg_flags */
+ DEBUG(0,("cli_net_auth2: error neg_flags (q,r) differ - (%x,%x)\n",
+ q_a.clnt_flgs.neg_flags, r_a.srv_flgs.neg_flags));
+ ok = False;
+ }
+#endif
+
+ }
+
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/****************************************************************************
+LSA Request Challenge. Sends our challenge to server, then gets
+server response. These are used to generate the credentials.
+****************************************************************************/
+
+BOOL cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ NET_Q_REQ_CHAL q_c;
+ BOOL valid_chal = False;
+
+ prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_REQCHAL */
+
+ DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s: %s\n",
+ cli->desthost, global_myname, credstr(clnt_chal->data)));
+
+ /* store the parameters */
+ init_q_req_chal(&q_c, cli->srv_name_slash,
+ global_myname, clnt_chal);
+
+ /* turn parameters into data stream */
+ if(!net_io_q_req_chal("", &q_c, &buf, 0)) {
+ DEBUG(0,("cli_net_req_chal: Error : failed to marshall NET_Q_REQ_CHAL struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_REQCHAL, &buf, &rbuf))
+ {
+ NET_R_REQ_CHAL r_c;
+ BOOL ok;
+
+ ok = net_io_r_req_chal("", &r_c, &rbuf, 0);
+
+ if (ok && !NT_STATUS_IS_OK(r_c.status))
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_req_chal: Error %s\n", get_nt_error_msg(r_c.status)));
+ ok = False;
+ }
+
+ if (ok)
+ {
+ /* ok, at last: we're happy. return the challenge */
+ memcpy(srv_chal, r_c.srv_chal.data, sizeof(srv_chal->data));
+ valid_chal = True;
+ }
+ }
+
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+
+ return valid_chal;
+}
+/***************************************************************************
+ LSA SAM Logon internal - interactive or network. Does level 2 or 3 but always
+ returns level 3.
+****************************************************************************/
+
+static NTSTATUS cli_net_sam_logon_internal(struct cli_state *cli, NET_ID_INFO_CTR *ctr,
+ NET_USER_INFO_3 *user_info3,
+ uint16 validation_level)
+{
+ DOM_CRED new_clnt_cred;
+ DOM_CRED dummy_rtn_creds;
+ prs_struct rbuf;
+ prs_struct buf;
+ NET_Q_SAM_LOGON q_s;
+ NET_R_SAM_LOGON r_s;
+ NTSTATUS retval = NT_STATUS_OK;
+
+ gen_next_creds( cli, &new_clnt_cred);
+
+ prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_SAMLOGON */
+
+ DEBUG(4,("cli_net_sam_logon_internal: srv:%s mc:%s clnt %s %x ll: %d\n",
+ cli->srv_name_slash, global_myname,
+ credstr(new_clnt_cred.challenge.data), cli->clnt_cred.timestamp.time,
+ ctr->switch_value));
+
+ memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
+ dummy_rtn_creds.timestamp.time = time(NULL);
+
+ /* store the parameters */
+ q_s.validation_level = validation_level;
+ init_sam_info(&q_s.sam_id, cli->srv_name_slash,
+ global_myname, &new_clnt_cred, &dummy_rtn_creds,
+ ctr->switch_value, ctr);
+
+ /* turn parameters into data stream */
+ if(!net_io_q_sam_logon("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_net_sam_logon_internal: Error : failed to marshall NET_Q_SAM_LOGON struct.\n"));
+ retval = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, NET_SAMLOGON, &buf, &rbuf)) {
+ DEBUG(0,("cli_net_sam_logon_internal: Error rpc_api_pipe_req failed.\n"));
+ retval = NT_STATUS_UNSUCCESSFUL;
+ goto out;
+ }
+
+ r_s.user = user_info3;
+
+ if(!net_io_r_sam_logon("", &r_s, &rbuf, 0)) {
+ DEBUG(0,("cli_net_sam_logon_internal: Error : failed to unmarshal NET_R_SAM_LOGON struct.\n"));
+ retval = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ retval = r_s.status;
+
+ /*
+ * Don't treat NT_STATUS_INVALID_INFO_CLASS as an error - we will re-issue
+ * the call.
+ */
+
+ if (NT_STATUS_V(retval) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
+ goto out;
+ }
+
+ if (!NT_STATUS_IS_OK(retval)) {
+ /* report error code */
+ DEBUG(0,("cli_net_sam_logon_internal: %s\n", get_nt_error_msg(r_s.status)));
+ goto out;
+ }
+
+ /* Update the credentials. */
+ if (!clnt_deal_with_creds(cli->sess_key, &cli->clnt_cred, &r_s.srv_creds)) {
+ /*
+ * Server replied with bad credential. Fail.
+ */
+ DEBUG(0,("cli_net_sam_logon_internal: server %s replied with bad credential (bad machine \
+password ?).\n", cli->desthost ));
+ retval = NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (r_s.switch_value != validation_level) {
+ /* report different switch_value */
+ DEBUG(0,("cli_net_sam_logon: switch_value of %x expected %x\n", (unsigned int)validation_level,
+ (unsigned int)r_s.switch_value));
+ retval = NT_STATUS_INVALID_PARAMETER;
+ }
+
+out:
+
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+
+ return retval;
+}
+
+/***************************************************************************
+LSA SAM Logon - interactive or network.
+****************************************************************************/
+
+NTSTATUS cli_net_sam_logon(struct cli_state *cli, NET_ID_INFO_CTR *ctr,
+ NET_USER_INFO_3 *user_info3)
+{
+ uint16 validation_level=3;
+ NTSTATUS result;
+
+ result = cli_net_sam_logon_internal(cli, ctr, user_info3,
+ validation_level);
+
+ if (NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("cli_net_sam_logon: Success \n"));
+ } else if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
+ DEBUG(10,("cli_net_sam_logon: STATUS INVALID INFO CLASS \n"));
+
+ validation_level=2;
+
+ /*
+ * Since this is the second time we call this function, don't care
+ * for the error. If its error, return False.
+ */
+
+ result = cli_net_sam_logon_internal(cli, ctr, user_info3,
+ validation_level);
+ }
+
+ return result;
+}
+
+/***************************************************************************
+LSA SAM Logoff.
+
+This currently doesnt work correctly as the domain controller
+returns NT_STATUS_INVALID_INFO_CLASS - we obviously need to
+send a different info level. Right now though, I'm not sure
+what that needs to be (I need to see one on the wire before
+I can be sure). JRA.
+****************************************************************************/
+BOOL cli_net_sam_logoff(struct cli_state *cli, NET_ID_INFO_CTR *ctr)
+{
+ DOM_CRED new_clnt_cred;
+ DOM_CRED dummy_rtn_creds;
+ prs_struct rbuf;
+ prs_struct buf;
+ NET_Q_SAM_LOGOFF q_s;
+ BOOL ok = False;
+
+ gen_next_creds( cli, &new_clnt_cred);
+
+ prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_SAMLOGOFF */
+
+ DEBUG(4,("cli_net_sam_logoff: srv:%s mc:%s clnt %s %x ll: %d\n",
+ cli->srv_name_slash, global_myname,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time,
+ ctr->switch_value));
+
+ memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
+
+ init_sam_info(&q_s.sam_id, cli->srv_name_slash,
+ global_myname, &new_clnt_cred, &dummy_rtn_creds,
+ ctr->switch_value, ctr);
+
+ /* turn parameters into data stream */
+ if(!net_io_q_sam_logoff("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_net_sam_logoff: Error : failed to marshall NET_Q_SAM_LOGOFF struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_SAMLOGOFF, &buf, &rbuf))
+ {
+ NET_R_SAM_LOGOFF r_s;
+
+ ok = net_io_r_sam_logoff("", &r_s, &rbuf, 0);
+
+ if (ok && !NT_STATUS_IS_OK(r_s.status))
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_sam_logoff: %s\n", get_nt_error_msg(r_s.status)));
+ ok = False;
+ }
+
+ /* Update the credentials. */
+ if (ok && !clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_creds)))
+ {
+ /*
+ * Server replied with bad credential. Fail.
+ */
+ DEBUG(0,("cli_net_sam_logoff: server %s replied with bad credential (bad machine \
+password ?).\n", cli->desthost ));
+ ok = False;
+ }
+ }
+
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+
+ return ok;
+}
diff --git a/source/rpc_client/cli_pipe.c b/source/rpc_client/cli_pipe.c
new file mode 100644
index 00000000000..6eaab39bcc7
--- /dev/null
+++ b/source/rpc_client/cli_pipe.c
@@ -0,0 +1,1260 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 1998.
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * 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"
+
+extern struct pipe_id_info pipe_names[];
+extern fstring global_myworkgroup;
+extern pstring global_myname;
+
+/********************************************************************
+ Rpc pipe call id.
+ ********************************************************************/
+
+static uint32 get_rpc_call_id(void)
+{
+ static uint32 call_id = 0;
+ return ++call_id;
+}
+
+/*******************************************************************
+ Use SMBreadX to get rest of one fragment's worth of rpc data.
+ ********************************************************************/
+
+static BOOL rpc_read(struct cli_state *cli, prs_struct *rdata, uint32 data_to_read, uint32 *rdata_offset)
+{
+ size_t size = (size_t)cli->max_recv_frag;
+ int stream_offset = 0;
+ int num_read;
+ char *pdata;
+ int extra_data_size = ((int)*rdata_offset) + ((int)data_to_read) - (int)prs_data_size(rdata);
+
+ DEBUG(5,("rpc_read: data_to_read: %u rdata offset: %u extra_data_size: %d\n",
+ (int)data_to_read, (unsigned int)*rdata_offset, extra_data_size));
+
+ /*
+ * Grow the buffer if needed to accommodate the data to be read.
+ */
+
+ if (extra_data_size > 0) {
+ if(!prs_force_grow(rdata, (uint32)extra_data_size)) {
+ DEBUG(0,("rpc_read: Failed to grow parse struct by %d bytes.\n", extra_data_size ));
+ return False;
+ }
+ DEBUG(5,("rpc_read: grew buffer by %d bytes to %u\n", extra_data_size, prs_data_size(rdata) ));
+ }
+
+ pdata = prs_data_p(rdata) + *rdata_offset;
+
+ do /* read data using SMBreadX */
+ {
+ uint32 ecode;
+ uint8 eclass;
+
+ if (size > (size_t)data_to_read)
+ size = (size_t)data_to_read;
+
+ num_read = (int)cli_read(cli, cli->nt_pipe_fnum, pdata, (off_t)stream_offset, size);
+
+ DEBUG(5,("rpc_read: num_read = %d, read offset: %d, to read: %d\n",
+ num_read, stream_offset, data_to_read));
+
+ if (cli_is_dos_error(cli)) {
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRDOS && ecode != ERRmoredata) {
+ DEBUG(0,("rpc_read: Error %d/%u in cli_read\n",
+ eclass, (unsigned int)ecode));
+ return False;
+ }
+ }
+
+ data_to_read -= num_read;
+ stream_offset += num_read;
+ pdata += num_read;
+
+ } while (num_read > 0 && data_to_read > 0);
+ /* && err == (0x80000000 | STATUS_BUFFER_OVERFLOW)); */
+
+ /*
+ * Update the current offset into rdata by the amount read.
+ */
+ *rdata_offset += stream_offset;
+
+ return True;
+}
+
+/****************************************************************************
+ Checks the header. This will set the endian bit in the rdata prs_struct. JRA.
+ ****************************************************************************/
+
+static BOOL rpc_check_hdr(prs_struct *rdata, RPC_HDR *rhdr,
+ BOOL *first, BOOL *last, uint32 *len)
+{
+ DEBUG(5,("rpc_check_hdr: rdata->data_size = %u\n", (uint32)prs_data_size(rdata) ));
+
+ /* Next call sets endian bit. */
+
+ if(!smb_io_rpc_hdr("rpc_hdr ", rhdr, rdata, 0)) {
+ DEBUG(0,("rpc_check_hdr: Failed to unmarshall RPC_HDR.\n"));
+ return False;
+ }
+
+ if (prs_offset(rdata) != RPC_HEADER_LEN) {
+ DEBUG(0,("rpc_check_hdr: offset was %x, should be %x.\n", prs_offset(rdata), RPC_HEADER_LEN));
+ return False;
+ }
+
+ (*first) = ((rhdr->flags & RPC_FLG_FIRST) != 0);
+ (*last) = ((rhdr->flags & RPC_FLG_LAST ) != 0);
+ (*len) = (uint32)rhdr->frag_len - prs_data_size(rdata);
+
+ return (rhdr->pkt_type != RPC_FAULT);
+}
+
+static void NTLMSSPcalc_ap( struct cli_state *cli, unsigned char *data, uint32 len)
+{
+ unsigned char *hash = cli->ntlmssp_hash;
+ unsigned char index_i = hash[256];
+ unsigned char index_j = hash[257];
+ int ind;
+
+ for( ind = 0; ind < len; ind++) {
+ unsigned char tc;
+ unsigned char t;
+
+ index_i++;
+ index_j += hash[index_i];
+
+ tc = hash[index_i];
+ hash[index_i] = hash[index_j];
+ hash[index_j] = tc;
+
+ t = hash[index_i] + hash[index_j];
+ data[ind] = data[ind] ^ hash[t];
+ }
+
+ hash[256] = index_i;
+ hash[257] = index_j;
+}
+
+/****************************************************************************
+ Verify data on an rpc pipe.
+ The VERIFY & SEAL code is only executed on packets that look like this :
+
+ Request/Response PDU's look like the following...
+
+ |<------------------PDU len----------------------------------------------->|
+ |<-HDR_LEN-->|<--REQ LEN------>|.............|<-AUTH_HDRLEN->|<-AUTH_LEN-->|
+
+ +------------+-----------------+-------------+---------------+-------------+
+ | RPC HEADER | REQ/RESP HEADER | DATA ...... | AUTH_HDR | AUTH DATA |
+ +------------+-----------------+-------------+---------------+-------------+
+
+ Never on bind requests/responses.
+ ****************************************************************************/
+
+static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata, int len, int auth_len)
+{
+ /*
+ * The following is that length of the data we must sign or seal.
+ * This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN
+ * preceeding the auth_data.
+ */
+
+ int data_len = len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len;
+
+ /*
+ * The start of the data to sign/seal is just after the RPC headers.
+ */
+ char *reply_data = prs_data_p(rdata) + RPC_HEADER_LEN + RPC_HDR_REQ_LEN;
+
+ BOOL auth_verify = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SIGN) != 0);
+ BOOL auth_seal = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SEAL) != 0);
+
+ DEBUG(5,("rpc_auth_pipe: len: %d auth_len: %d verify %s seal %s\n",
+ len, auth_len, BOOLSTR(auth_verify), BOOLSTR(auth_seal)));
+
+ /*
+ * Unseal any sealed data in the PDU, not including the
+ * 8 byte auth_header or the auth_data.
+ */
+
+ if (auth_seal) {
+ DEBUG(10,("rpc_auth_pipe: unseal\n"));
+ dump_data(100, reply_data, data_len);
+ NTLMSSPcalc_ap(cli, (uchar*)reply_data, data_len);
+ dump_data(100, reply_data, data_len);
+ }
+
+ if (auth_verify || auth_seal) {
+ RPC_HDR_AUTH rhdr_auth;
+ prs_struct auth_req;
+ char data[RPC_HDR_AUTH_LEN];
+ /*
+ * We set dp to be the end of the packet, minus the auth_len
+ * and the length of the header that preceeds the auth_data.
+ */
+ char *dp = prs_data_p(rdata) + len - auth_len - RPC_HDR_AUTH_LEN;
+
+ if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+ DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+ return False;
+ }
+
+ memcpy(data, dp, sizeof(data));
+
+ prs_init(&auth_req , 0, cli->mem_ctx, UNMARSHALL);
+
+ /* The endianness must be preserved... JRA. */
+
+ prs_set_endian_data(&auth_req, rdata->bigendian_data);
+
+ prs_give_memory(&auth_req, data, RPC_HDR_AUTH_LEN, False);
+
+ /*
+ * Unmarshall the 8 byte auth_header that comes before the
+ * auth data.
+ */
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &rhdr_auth, &auth_req, 0)) {
+ DEBUG(0,("rpc_auth_pipe: unmarshalling RPC_HDR_AUTH failed.\n"));
+ return False;
+ }
+
+ if (!rpc_hdr_auth_chk(&rhdr_auth)) {
+ DEBUG(0,("rpc_auth_pipe: rpc_hdr_auth_chk failed.\n"));
+ return False;
+ }
+ }
+
+ /*
+ * Now unseal and check the auth verifier in the auth_data at
+ * then end of the packet. The 4 bytes skipped in the unseal
+ * seem to be a buffer pointer preceeding the sealed data.
+ */
+
+ if (auth_verify) {
+ RPC_AUTH_NTLMSSP_CHK chk;
+ uint32 crc32;
+ prs_struct auth_verf;
+ char data[RPC_AUTH_NTLMSSP_CHK_LEN];
+ char *dp = prs_data_p(rdata) + len - auth_len;
+
+ if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+ DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+ return False;
+ }
+
+ DEBUG(10,("rpc_auth_pipe: verify\n"));
+ dump_data(100, dp, auth_len);
+ NTLMSSPcalc_ap(cli, (uchar*)(dp+4), auth_len - 4);
+
+ memcpy(data, dp, RPC_AUTH_NTLMSSP_CHK_LEN);
+ dump_data(100, data, auth_len);
+
+ prs_init(&auth_verf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* The endinness must be preserved. JRA. */
+ prs_set_endian_data( &auth_verf, rdata->bigendian_data);
+
+ prs_give_memory(&auth_verf, data, RPC_AUTH_NTLMSSP_CHK_LEN, False);
+
+ if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &chk, &auth_verf, 0)) {
+ DEBUG(0,("rpc_auth_pipe: unmarshalling RPC_AUTH_NTLMSSP_CHK failed.\n"));
+ return False;
+ }
+
+ crc32 = crc32_calc_buffer(reply_data, data_len);
+
+ if (!rpc_auth_ntlmssp_chk(&chk, crc32 , cli->ntlmssp_seq_num)) {
+ DEBUG(0,("rpc_auth_pipe: rpc_auth_ntlmssp_chk failed.\n"));
+ return False;
+ }
+ cli->ntlmssp_seq_num++;
+ }
+ return True;
+}
+
+
+/****************************************************************************
+ Send data on an rpc pipe, which *must* be in one fragment.
+ receive response data from an rpc pipe, which may be large...
+
+ Read the first fragment: unfortunately have to use SMBtrans for the first
+ bit, then SMBreadX for subsequent bits.
+
+ If first fragment received also wasn't the last fragment, continue
+ getting fragments until we _do_ receive the last fragment.
+
+ Request/Response PDU's look like the following...
+
+ |<------------------PDU len----------------------------------------------->|
+ |<-HDR_LEN-->|<--REQ LEN------>|.............|<-AUTH_HDRLEN->|<-AUTH_LEN-->|
+
+ +------------+-----------------+-------------+---------------+-------------+
+ | RPC HEADER | REQ/RESP HEADER | DATA ...... | AUTH_HDR | AUTH DATA |
+ +------------+-----------------+-------------+---------------+-------------+
+
+ Where the presence of the AUTH_HDR and AUTH are dependent on the
+ signing & sealing being neogitated.
+
+ ****************************************************************************/
+
+static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd, prs_struct *data, prs_struct *rdata)
+{
+ uint32 len;
+ char *rparam = NULL;
+ uint32 rparam_len = 0;
+ uint16 setup[2];
+ BOOL first = True;
+ BOOL last = True;
+ RPC_HDR rhdr;
+ char *pdata = data ? prs_data_p(data) : NULL;
+ uint32 data_len = data ? prs_offset(data) : 0;
+ char *prdata = NULL;
+ uint32 rdata_len = 0;
+ uint32 current_offset = 0;
+
+ /* Create setup parameters - must be in native byte order. */
+
+ setup[0] = cmd;
+ setup[1] = cli->nt_pipe_fnum; /* Pipe file handle. */
+
+ DEBUG(5,("rpc_api_pipe: cmd:%x fnum:%x\n", (int)cmd,
+ (int)cli->nt_pipe_fnum));
+
+ /* Send the RPC request and receive a response. For short RPC
+ calls (about 1024 bytes or so) the RPC request and response
+ appears in a SMBtrans request and response. Larger RPC
+ responses are received further on. */
+
+ if (!cli_api_pipe(cli, "\\PIPE\\",
+ setup, 2, 0, /* Setup, length, max */
+ NULL, 0, 0, /* Params, length, max */
+ pdata, data_len, data_len, /* data, length, max */
+ &rparam, &rparam_len, /* return params, len */
+ &prdata, &rdata_len)) /* return data, len */
+ {
+ DEBUG(0, ("cli_pipe: return critical error. Error was %s\n", cli_errstr(cli)));
+ return False;
+ }
+
+ /* Throw away returned params - we know we won't use them. */
+
+ SAFE_FREE(rparam);
+
+ if (prdata == NULL) {
+ DEBUG(0,("rpc_api_pipe: cmd %x on pipe %x failed to return data.\n",
+ (int)cmd, (int)cli->nt_pipe_fnum));
+ return False;
+ }
+
+ /*
+ * Give this memory as dynamically allocated to the return parse
+ * struct.
+ */
+
+ prs_give_memory(rdata, prdata, rdata_len, True);
+ current_offset = rdata_len;
+
+ /* This next call sets the endian bit correctly in rdata. */
+
+ if (!rpc_check_hdr(rdata, &rhdr, &first, &last, &len)) {
+ prs_mem_free(rdata);
+ return False;
+ }
+
+ if (rhdr.pkt_type == RPC_BINDACK) {
+ if (!last && !first) {
+ DEBUG(5,("rpc_api_pipe: bug in server (AS/U?), setting fragment first/last ON.\n"));
+ first = True;
+ last = True;
+ }
+ }
+
+ if (rhdr.pkt_type == RPC_RESPONSE) {
+ RPC_HDR_RESP rhdr_resp;
+ if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, rdata, 0)) {
+ DEBUG(5,("rpc_api_pipe: failed to unmarshal RPC_HDR_RESP.\n"));
+ prs_mem_free(rdata);
+ return False;
+ }
+ }
+
+ DEBUG(5,("rpc_api_pipe: len left: %u smbtrans read: %u\n",
+ (unsigned int)len, (unsigned int)rdata_len ));
+
+ /* check if data to be sent back was too large for one SMBtrans */
+ /* err status is only informational: the _real_ check is on the
+ length */
+
+ if (len > 0) {
+ /* || err == (0x80000000 | STATUS_BUFFER_OVERFLOW)) */
+
+ /* Read the remaining part of the first response fragment */
+
+ if (!rpc_read(cli, rdata, len, &current_offset)) {
+ prs_mem_free(rdata);
+ return False;
+ }
+ }
+
+ /*
+ * Now we have a complete PDU, check the auth struct if any was sent.
+ */
+
+ if (rhdr.auth_len != 0) {
+ if(!rpc_auth_pipe(cli, rdata, rhdr.frag_len, rhdr.auth_len))
+ return False;
+ /*
+ * Drop the auth footers from the current offset.
+ * We need this if there are more fragments.
+ * The auth footers consist of the auth_data and the
+ * preceeding 8 byte auth_header.
+ */
+ current_offset -= (rhdr.auth_len + RPC_HDR_AUTH_LEN);
+ }
+
+ /*
+ * Only one rpc fragment, and it has been read.
+ */
+
+ if (first && last) {
+ DEBUG(6,("rpc_api_pipe: fragment first and last both set\n"));
+ return True;
+ }
+
+ /*
+ * Read more fragments using SMBreadX until we get one with the
+ * last bit set.
+ */
+
+ while (!last) {
+ RPC_HDR_RESP rhdr_resp;
+ int num_read;
+ char hdr_data[RPC_HEADER_LEN+RPC_HDR_RESP_LEN];
+ prs_struct hps;
+ uint8 eclass;
+ uint32 ecode;
+
+ /*
+ * First read the header of the next PDU.
+ */
+
+ prs_init(&hps, 0, cli->mem_ctx, UNMARSHALL);
+ prs_give_memory(&hps, hdr_data, sizeof(hdr_data), False);
+
+ num_read = cli_read(cli, cli->nt_pipe_fnum, hdr_data, 0, RPC_HEADER_LEN+RPC_HDR_RESP_LEN);
+ if (cli_is_dos_error(cli)) {
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRDOS && ecode != ERRmoredata) {
+ DEBUG(0,("rpc_api_pipe: cli_read error : %d/%d\n", eclass, ecode));
+ return False;
+ }
+ }
+
+ DEBUG(5,("rpc_api_pipe: read header (size:%d)\n", num_read));
+
+ if (num_read != RPC_HEADER_LEN+RPC_HDR_RESP_LEN) {
+ DEBUG(0,("rpc_api_pipe: Error : requested %d bytes, got %d.\n",
+ RPC_HEADER_LEN+RPC_HDR_RESP_LEN, num_read ));
+ return False;
+ }
+
+ /* This call sets the endianness in hps. */
+
+ if (!rpc_check_hdr(&hps, &rhdr, &first, &last, &len))
+ return False;
+
+ /* Ensure the endianness in rdata is set correctly - must be same as hps. */
+
+ if (hps.bigendian_data != rdata->bigendian_data) {
+ DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to %s\n",
+ rdata->bigendian_data ? "big" : "little",
+ hps.bigendian_data ? "big" : "little" ));
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, &hps, 0)) {
+ DEBUG(0,("rpc_api_pipe: Error in unmarshalling RPC_HDR_RESP.\n"));
+ return False;
+ }
+
+ if (first) {
+ DEBUG(0,("rpc_api_pipe: secondary PDU rpc header has 'first' set !\n"));
+ return False;
+ }
+
+ /*
+ * Now read the rest of the PDU.
+ */
+
+ if (!rpc_read(cli, rdata, len, &current_offset))
+ return False;
+
+ /*
+ * Verify any authentication footer.
+ */
+
+ if (rhdr.auth_len != 0 ) {
+ if(!rpc_auth_pipe(cli, rdata, rhdr.frag_len, rhdr.auth_len))
+ return False;
+ /*
+ * Drop the auth footers from the current offset.
+ * The auth footers consist of the auth_data and the
+ * preceeding 8 byte auth_header.
+ * We need this if there are more fragments.
+ */
+ current_offset -= (rhdr.auth_len + RPC_HDR_AUTH_LEN);
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ creates a DCE/RPC bind request
+
+ - initialises the parse structure.
+ - dynamically allocates the header data structure
+ - caller is expected to free the header data structure once used.
+
+ ********************************************************************/
+
+static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, uint32 rpc_call_id,
+ RPC_IFACE *abstract, RPC_IFACE *transfer,
+ char *my_name, char *domain, uint32 neg_flags)
+{
+ RPC_HDR hdr;
+ RPC_HDR_RB hdr_rb;
+ char buffer[4096];
+ prs_struct auth_info;
+ int auth_len = 0;
+
+ prs_init(&auth_info, 0, prs_get_mem_context(rpc_out), MARSHALL);
+
+ if (do_auth) {
+ RPC_HDR_AUTH hdr_auth;
+ RPC_AUTH_VERIFIER auth_verifier;
+ RPC_AUTH_NTLMSSP_NEG ntlmssp_neg;
+
+ /*
+ * Create the auth structs we will marshall.
+ */
+
+ init_rpc_hdr_auth(&hdr_auth, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, 0x00, 1);
+ init_rpc_auth_verifier(&auth_verifier, "NTLMSSP", NTLMSSP_NEGOTIATE);
+ init_rpc_auth_ntlmssp_neg(&ntlmssp_neg, neg_flags, my_name, domain);
+
+ /*
+ * Use the 4k buffer to store the auth info.
+ */
+
+ prs_give_memory( &auth_info, buffer, sizeof(buffer), False);
+
+ /*
+ * Now marshall the data into the temporary parse_struct.
+ */
+
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &auth_info, 0)) {
+ DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR_AUTH.\n"));
+ return False;
+ }
+
+ if(!smb_io_rpc_auth_verifier("auth_verifier", &auth_verifier, &auth_info, 0)) {
+ DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_AUTH_VERIFIER.\n"));
+ return False;
+ }
+
+ if(!smb_io_rpc_auth_ntlmssp_neg("ntlmssp_neg", &ntlmssp_neg, &auth_info, 0)) {
+ DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_AUTH_NTLMSSP_NEG.\n"));
+ return False;
+ }
+
+ /* Auth len in the rpc header doesn't include auth_header. */
+ auth_len = prs_offset(&auth_info) - RPC_HDR_AUTH_LEN;
+ }
+
+ /* create the request RPC_HDR */
+ init_rpc_hdr(&hdr, RPC_BIND, 0x0, rpc_call_id,
+ RPC_HEADER_LEN + RPC_HDR_RB_LEN + prs_offset(&auth_info),
+ auth_len);
+
+ if(!smb_io_rpc_hdr("hdr" , &hdr, rpc_out, 0)) {
+ DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR.\n"));
+ return False;
+ }
+
+ /* create the bind request RPC_HDR_RB */
+ init_rpc_hdr_rb(&hdr_rb, MAX_PDU_FRAG_LEN, MAX_PDU_FRAG_LEN, 0x0,
+ 0x1, 0x0, 0x1, abstract, transfer);
+
+ /* Marshall the bind request data */
+ if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_out, 0)) {
+ DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR_RB.\n"));
+ return False;
+ }
+
+ /*
+ * Grow the outgoing buffer to store any auth info.
+ */
+
+ if(hdr.auth_len != 0) {
+ if(!prs_append_prs_data( rpc_out, &auth_info)) {
+ DEBUG(0,("create_rpc_bind_req: failed to grow parse struct to add auth.\n"));
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ Creates a DCE/RPC bind authentication response.
+ This is the packet that is sent back to the server once we
+ have received a BIND-ACK, to finish the third leg of
+ the authentication handshake.
+ ********************************************************************/
+
+static BOOL create_rpc_bind_resp(struct pwd_info *pwd,
+ char *domain, char *user_name, char *my_name,
+ uint32 ntlmssp_cli_flgs,
+ uint32 rpc_call_id,
+ prs_struct *rpc_out)
+{
+ unsigned char lm_owf[24];
+ unsigned char nt_owf[24];
+ RPC_HDR hdr;
+ RPC_HDR_AUTHA hdr_autha;
+ RPC_AUTH_VERIFIER auth_verifier;
+ RPC_AUTH_NTLMSSP_RESP ntlmssp_resp;
+ char buffer[4096];
+ prs_struct auth_info;
+
+ /*
+ * Marshall the variable length data into a temporary parse
+ * struct, pointing into a 4k local buffer.
+ */
+ prs_init(&auth_info, 0, prs_get_mem_context(rpc_out), MARSHALL);
+
+ /*
+ * Use the 4k buffer to store the auth info.
+ */
+
+ prs_give_memory( &auth_info, buffer, sizeof(buffer), False);
+
+ /*
+ * Create the variable length auth_data.
+ */
+
+ init_rpc_auth_verifier(&auth_verifier, "NTLMSSP", NTLMSSP_AUTH);
+
+ pwd_get_lm_nt_owf(pwd, lm_owf, nt_owf);
+
+ init_rpc_auth_ntlmssp_resp(&ntlmssp_resp,
+ lm_owf, nt_owf,
+ domain, user_name, my_name,
+ ntlmssp_cli_flgs);
+
+ /*
+ * Marshall the variable length auth_data into a temp parse_struct.
+ */
+
+ if(!smb_io_rpc_auth_verifier("auth_verifier", &auth_verifier, &auth_info, 0)) {
+ DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_AUTH_VERIFIER.\n"));
+ return False;
+ }
+
+ if(!smb_io_rpc_auth_ntlmssp_resp("ntlmssp_resp", &ntlmssp_resp, &auth_info, 0)) {
+ DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_AUTH_NTLMSSP_RESP.\n"));
+ return False;
+ }
+
+ /* Create the request RPC_HDR */
+ init_rpc_hdr(&hdr, RPC_BINDRESP, 0x0, rpc_call_id,
+ RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN + prs_offset(&auth_info),
+ prs_offset(&auth_info) );
+
+ /* Marshall it. */
+ if(!smb_io_rpc_hdr("hdr", &hdr, rpc_out, 0)) {
+ DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_HDR.\n"));
+ return False;
+ }
+
+ /* Create the request RPC_HDR_AUTHA */
+ init_rpc_hdr_autha(&hdr_autha, MAX_PDU_FRAG_LEN, MAX_PDU_FRAG_LEN,
+ NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, 0x00);
+
+ if(!smb_io_rpc_hdr_autha("hdr_autha", &hdr_autha, rpc_out, 0)) {
+ DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_HDR_AUTHA.\n"));
+ return False;
+ }
+
+ /*
+ * Append the auth data to the outgoing buffer.
+ */
+
+ if(!prs_append_prs_data(rpc_out, &auth_info)) {
+ DEBUG(0,("create_rpc_bind_req: failed to grow parse struct to add auth.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/*******************************************************************
+ Creates a DCE/RPC request.
+ ********************************************************************/
+
+static BOOL create_rpc_request(prs_struct *rpc_out, uint8 op_num, int data_len, int auth_len)
+{
+ uint32 alloc_hint;
+ RPC_HDR hdr;
+ RPC_HDR_REQ hdr_req;
+
+ DEBUG(5,("create_rpc_request: opnum: 0x%x data_len: 0x%x\n", op_num, data_len));
+
+ /* create the rpc header RPC_HDR */
+ init_rpc_hdr(&hdr, RPC_REQUEST, RPC_FLG_FIRST | RPC_FLG_LAST,
+ get_rpc_call_id(), data_len, auth_len);
+
+ /*
+ * The alloc hint should be the amount of data, not including
+ * RPC headers & footers.
+ */
+
+ if (auth_len != 0)
+ alloc_hint = data_len - RPC_HEADER_LEN - RPC_HDR_AUTH_LEN - auth_len;
+ else
+ alloc_hint = data_len - RPC_HEADER_LEN;
+
+ DEBUG(10,("create_rpc_request: data_len: %x auth_len: %x alloc_hint: %x\n",
+ data_len, auth_len, alloc_hint));
+
+ /* Create the rpc request RPC_HDR_REQ */
+ init_rpc_hdr_req(&hdr_req, alloc_hint, op_num);
+
+ /* stream-time... */
+ if(!smb_io_rpc_hdr("hdr ", &hdr, rpc_out, 0))
+ return False;
+
+ if(!smb_io_rpc_hdr_req("hdr_req", &hdr_req, rpc_out, 0))
+ return False;
+
+ if (prs_offset(rpc_out) != RPC_HEADER_LEN + RPC_HDR_REQ_LEN)
+ return False;
+
+ return True;
+}
+
+
+/****************************************************************************
+ Send a request on an rpc pipe.
+ ****************************************************************************/
+
+BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
+ prs_struct *data, prs_struct *rdata)
+{
+ prs_struct outgoing_packet;
+ uint32 data_len;
+ uint32 auth_len;
+ BOOL ret;
+ BOOL auth_verify;
+ BOOL auth_seal;
+ uint32 crc32 = 0;
+ char *pdata_out = NULL;
+
+ auth_verify = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SIGN) != 0);
+ auth_seal = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SEAL) != 0);
+
+ /*
+ * The auth_len doesn't include the RPC_HDR_AUTH_LEN.
+ */
+
+ auth_len = (auth_verify ? RPC_AUTH_NTLMSSP_CHK_LEN : 0);
+
+ /*
+ * PDU len is header, plus request header, plus data, plus
+ * auth_header_len (if present), plus auth_len (if present).
+ * NB. The auth stuff should be aligned on an 8 byte boundary
+ * to be totally DCE/RPC spec complient. For now we cheat and
+ * hope that the data structs defined are a multiple of 8 bytes.
+ */
+
+ if((prs_offset(data) % 8) != 0) {
+ DEBUG(5,("rpc_api_pipe_req: Outgoing data not a multiple of 8 bytes....\n"));
+ }
+
+ data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + prs_offset(data) +
+ (auth_verify ? RPC_HDR_AUTH_LEN : 0) + auth_len;
+
+ /*
+ * Malloc a parse struct to hold it (and enough for alignments).
+ */
+
+ if(!prs_init(&outgoing_packet, data_len + 8, cli->mem_ctx, MARSHALL)) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to malloc %u bytes.\n", (unsigned int)data_len ));
+ return False;
+ }
+
+ pdata_out = prs_data_p(&outgoing_packet);
+
+ /*
+ * Write out the RPC header and the request header.
+ */
+
+ if(!create_rpc_request(&outgoing_packet, op_num, data_len, auth_len)) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to create RPC request.\n"));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+
+ /*
+ * Seal the outgoing data if requested.
+ */
+
+ if (auth_seal) {
+ crc32 = crc32_calc_buffer(prs_data_p(data), prs_offset(data));
+ NTLMSSPcalc_ap(cli, (unsigned char*)prs_data_p(data), prs_offset(data));
+ }
+
+ /*
+ * Now copy the data into the outgoing packet.
+ */
+
+ if(!prs_append_prs_data( &outgoing_packet, data)) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to append data to outgoing packet.\n"));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+
+ /*
+ * Add a trailing auth_verifier if needed.
+ */
+
+ if (auth_seal || auth_verify) {
+ RPC_HDR_AUTH hdr_auth;
+
+ init_rpc_hdr_auth(&hdr_auth, NTLMSSP_AUTH_TYPE,
+ NTLMSSP_AUTH_LEVEL, 0x08, (auth_verify ? 1 : 0));
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &outgoing_packet, 0)) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to marshal RPC_HDR_AUTH.\n"));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+ }
+
+ /*
+ * Finally the auth data itself.
+ */
+
+ if (auth_verify) {
+ RPC_AUTH_NTLMSSP_CHK chk;
+ uint32 current_offset = prs_offset(&outgoing_packet);
+
+ init_rpc_auth_ntlmssp_chk(&chk, NTLMSSP_SIGN_VERSION, crc32, cli->ntlmssp_seq_num++);
+ if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &chk, &outgoing_packet, 0)) {
+ DEBUG(0,("rpc_api_pipe_req: Failed to marshal RPC_AUTH_NTLMSSP_CHK.\n"));
+ prs_mem_free(&outgoing_packet);
+ return False;
+ }
+ NTLMSSPcalc_ap(cli, (unsigned char*)&pdata_out[current_offset+4], RPC_AUTH_NTLMSSP_CHK_LEN - 4);
+ }
+
+ DEBUG(100,("data_len: %x data_calc_len: %x\n", data_len, prs_offset(&outgoing_packet)));
+
+ ret = rpc_api_pipe(cli, 0x0026, &outgoing_packet, rdata);
+
+ prs_mem_free(&outgoing_packet);
+
+ return ret;
+}
+
+/****************************************************************************
+ Set the handle state.
+****************************************************************************/
+
+static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, const char *pipe_name, uint16 device_state)
+{
+ BOOL state_set = False;
+ char param[2];
+ uint16 setup[2]; /* only need 2 uint16 setup parameters */
+ char *rparam = NULL;
+ char *rdata = NULL;
+ uint32 rparam_len, rdata_len;
+
+ if (pipe_name == NULL)
+ return False;
+
+ DEBUG(5,("Set Handle state Pipe[%x]: %s - device state:%x\n",
+ cli->nt_pipe_fnum, pipe_name, device_state));
+
+ /* create parameters: device state */
+ SSVAL(param, 0, device_state);
+
+ /* create setup parameters. */
+ setup[0] = 0x0001;
+ setup[1] = cli->nt_pipe_fnum; /* pipe file handle. got this from an SMBOpenX. */
+
+ /* send the data on \PIPE\ */
+ if (cli_api_pipe(cli, "\\PIPE\\",
+ setup, 2, 0, /* setup, length, max */
+ param, 2, 0, /* param, length, max */
+ NULL, 0, 1024, /* data, length, max */
+ &rparam, &rparam_len, /* return param, length */
+ &rdata, &rdata_len)) /* return data, length */
+ {
+ DEBUG(5, ("Set Handle state: return OK\n"));
+ state_set = True;
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return state_set;
+}
+
+/****************************************************************************
+ check the rpc bind acknowledge response
+****************************************************************************/
+
+static BOOL valid_pipe_name(const char *pipe_name, RPC_IFACE *abstract, RPC_IFACE *transfer)
+{
+ int pipe_idx = 0;
+
+ while (pipe_names[pipe_idx].client_pipe != NULL) {
+ if (strequal(pipe_name, pipe_names[pipe_idx].client_pipe )) {
+ DEBUG(5,("Bind Abstract Syntax: "));
+ dump_data(5, (char*)&(pipe_names[pipe_idx].abstr_syntax),
+ sizeof(pipe_names[pipe_idx].abstr_syntax));
+ DEBUG(5,("Bind Transfer Syntax: "));
+ dump_data(5, (char*)&(pipe_names[pipe_idx].trans_syntax),
+ sizeof(pipe_names[pipe_idx].trans_syntax));
+
+ /* copy the required syntaxes out so we can do the right bind */
+ *transfer = pipe_names[pipe_idx].trans_syntax;
+ *abstract = pipe_names[pipe_idx].abstr_syntax;
+
+ return True;
+ }
+ pipe_idx++;
+ };
+
+ DEBUG(5,("Bind RPC Pipe[%s] unsupported\n", pipe_name));
+ return False;
+}
+
+/****************************************************************************
+ check the rpc bind acknowledge response
+****************************************************************************/
+
+static BOOL check_bind_response(RPC_HDR_BA *hdr_ba, const char *pipe_name, RPC_IFACE *transfer)
+{
+ int i = 0;
+
+ while ((pipe_names[i].client_pipe != NULL) && hdr_ba->addr.len > 0) {
+ if ((strequal(pipe_name, pipe_names[i].client_pipe ))) {
+ if (strequal(hdr_ba->addr.str, pipe_names[i].server_pipe )) {
+ DEBUG(5,("bind_rpc_pipe: server pipe_name found: %s\n",
+ pipe_names[i].server_pipe ));
+ break;
+ } else {
+ DEBUG(4,("bind_rpc_pipe: pipe_name %s != expected pipe %s. oh well!\n",
+ pipe_names[i].server_pipe ,
+ hdr_ba->addr.str));
+ break;
+ }
+ } else {
+ i++;
+ }
+ }
+
+ if (pipe_names[i].server_pipe == NULL) {
+ DEBUG(2,("bind_rpc_pipe: pipe name %s unsupported\n", hdr_ba->addr.str));
+ return False;
+ }
+
+ /* check the transfer syntax */
+ if ((hdr_ba->transfer.version != transfer->version) ||
+ (memcmp(&hdr_ba->transfer.uuid, &transfer->uuid, sizeof(transfer->uuid)) !=0)) {
+ DEBUG(0,("bind_rpc_pipe: transfer syntax differs\n"));
+ return False;
+ }
+
+ /* lkclXXXX only accept one result: check the result(s) */
+ if (hdr_ba->res.num_results != 0x1 || hdr_ba->res.result != 0) {
+ DEBUG(2,("bind_rpc_pipe: bind denied results: %d reason: %x\n",
+ hdr_ba->res.num_results, hdr_ba->res.reason));
+ }
+
+ DEBUG(5,("bind_rpc_pipe: accepted!\n"));
+ return True;
+}
+
+/****************************************************************************
+ Create and send the third packet in an RPC auth.
+****************************************************************************/
+
+static BOOL rpc_send_auth_reply(struct cli_state *cli, prs_struct *rdata, uint32 rpc_call_id)
+{
+ RPC_HDR_AUTH rhdr_auth;
+ RPC_AUTH_VERIFIER rhdr_verf;
+ RPC_AUTH_NTLMSSP_CHAL rhdr_chal;
+ char buffer[MAX_PDU_FRAG_LEN];
+ prs_struct rpc_out;
+ ssize_t ret;
+
+ unsigned char p24[24];
+ unsigned char lm_owf[24];
+ unsigned char lm_hash[16];
+
+ if(!smb_io_rpc_hdr_auth("", &rhdr_auth, rdata, 0)) {
+ DEBUG(0,("rpc_send_auth_reply: Failed to unmarshall RPC_HDR_AUTH.\n"));
+ return False;
+ }
+ if(!smb_io_rpc_auth_verifier("", &rhdr_verf, rdata, 0)) {
+ DEBUG(0,("rpc_send_auth_reply: Failed to unmarshall RPC_AUTH_VERIFIER.\n"));
+ return False;
+ }
+ if(!smb_io_rpc_auth_ntlmssp_chal("", &rhdr_chal, rdata, 0)) {
+ DEBUG(0,("rpc_send_auth_reply: Failed to unmarshall RPC_AUTH_NTLMSSP_CHAL.\n"));
+ return False;
+ }
+
+ cli->ntlmssp_cli_flgs = rhdr_chal.neg_flags;
+
+ pwd_make_lm_nt_owf(&cli->pwd, rhdr_chal.challenge);
+
+ prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL);
+
+ prs_give_memory( &rpc_out, buffer, sizeof(buffer), False);
+
+ create_rpc_bind_resp(&cli->pwd, cli->domain,
+ cli->user_name, global_myname,
+ cli->ntlmssp_cli_flgs, rpc_call_id,
+ &rpc_out);
+
+ pwd_get_lm_nt_owf(&cli->pwd, lm_owf, NULL);
+ pwd_get_lm_nt_16(&cli->pwd, lm_hash, NULL);
+
+ NTLMSSPOWFencrypt(lm_hash, lm_owf, p24);
+
+ {
+ unsigned char j = 0;
+ int ind;
+ unsigned char k2[8];
+
+ memcpy(k2, p24, 5);
+ k2[5] = 0xe5;
+ k2[6] = 0x38;
+ k2[7] = 0xb0;
+
+ for (ind = 0; ind < 256; ind++)
+ cli->ntlmssp_hash[ind] = (unsigned char)ind;
+
+ for( ind = 0; ind < 256; ind++) {
+ unsigned char tc;
+
+ j += (cli->ntlmssp_hash[ind] + k2[ind%8]);
+
+ tc = cli->ntlmssp_hash[ind];
+ cli->ntlmssp_hash[ind] = cli->ntlmssp_hash[j];
+ cli->ntlmssp_hash[j] = tc;
+ }
+
+ cli->ntlmssp_hash[256] = 0;
+ cli->ntlmssp_hash[257] = 0;
+ }
+
+ memset((char *)lm_hash, '\0', sizeof(lm_hash));
+
+ if ((ret = cli_write(cli, cli->nt_pipe_fnum, 0x8, prs_data_p(&rpc_out),
+ 0, (size_t)prs_offset(&rpc_out))) != (ssize_t)prs_offset(&rpc_out)) {
+ DEBUG(0,("rpc_send_auth_reply: cli_write failed. Return was %d\n", (int)ret));
+ return False;
+ }
+
+ cli->ntlmssp_srv_flgs = rhdr_chal.neg_flags;
+ return True;
+}
+
+/****************************************************************************
+ Do an rpc bind.
+****************************************************************************/
+
+BOOL rpc_pipe_bind(struct cli_state *cli, const char *pipe_name, char *my_name)
+{
+ RPC_IFACE abstract;
+ RPC_IFACE transfer;
+ prs_struct rpc_out;
+ prs_struct rdata;
+ BOOL do_auth = (cli->ntlmssp_cli_flgs != 0);
+ uint32 rpc_call_id;
+ char buffer[MAX_PDU_FRAG_LEN];
+
+ DEBUG(5,("Bind RPC Pipe[%x]: %s\n", cli->nt_pipe_fnum, pipe_name));
+
+ if (!valid_pipe_name(pipe_name, &abstract, &transfer))
+ return False;
+
+ prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL);
+
+ /*
+ * Use the MAX_PDU_FRAG_LEN buffer to store the bind request.
+ */
+
+ prs_give_memory( &rpc_out, buffer, sizeof(buffer), False);
+
+ rpc_call_id = get_rpc_call_id();
+
+ /* Marshall the outgoing data. */
+ create_rpc_bind_req(&rpc_out, do_auth, rpc_call_id,
+ &abstract, &transfer,
+ global_myname, cli->domain, cli->ntlmssp_cli_flgs);
+
+ /* Initialize the incoming data struct. */
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* send data on \PIPE\. receive a response */
+ if (rpc_api_pipe(cli, 0x0026, &rpc_out, &rdata)) {
+ RPC_HDR_BA hdr_ba;
+
+ DEBUG(5, ("rpc_pipe_bind: rpc_api_pipe returned OK.\n"));
+
+ if(!smb_io_rpc_hdr_ba("", &hdr_ba, &rdata, 0)) {
+ DEBUG(0,("rpc_pipe_bind: Failed to unmarshall RPC_HDR_BA.\n"));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if(!check_bind_response(&hdr_ba, pipe_name, &transfer)) {
+ DEBUG(0,("rpc_pipe_bind: check_bind_response failed.\n"));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ cli->max_xmit_frag = hdr_ba.bba.max_tsize;
+ cli->max_recv_frag = hdr_ba.bba.max_rsize;
+
+ /*
+ * If we're doing NTLMSSP auth we need to send a reply to
+ * the bind-ack to complete the 3-way challenge response
+ * handshake.
+ */
+
+ if (do_auth && !rpc_send_auth_reply(cli, &rdata, rpc_call_id)) {
+ DEBUG(0,("rpc_pipe_bind: rpc_send_auth_reply failed.\n"));
+ prs_mem_free(&rdata);
+ return False;
+ }
+ }
+
+ prs_mem_free(&rdata);
+ return True;
+}
+
+/****************************************************************************
+ Set ntlmssp negotiation flags.
+ ****************************************************************************/
+
+void cli_nt_set_ntlmssp_flgs(struct cli_state *cli, uint32 ntlmssp_flgs)
+{
+ cli->ntlmssp_cli_flgs = ntlmssp_flgs;
+}
+
+
+/****************************************************************************
+ Open a session.
+ ****************************************************************************/
+
+BOOL cli_nt_session_open(struct cli_state *cli, const char *pipe_name)
+{
+ int fnum;
+
+ SMB_ASSERT(cli->nt_pipe_fnum == 0);
+
+ if (cli->capabilities & CAP_NT_SMBS) {
+ if ((fnum = cli_nt_create(cli, &pipe_name[5], DESIRED_ACCESS_PIPE)) == -1) {
+ DEBUG(0,("cli_nt_session_open: cli_nt_create failed on pipe %s to machine %s. Error was %s\n",
+ &pipe_name[5], cli->desthost, cli_errstr(cli)));
+ return False;
+ }
+
+ cli->nt_pipe_fnum = (uint16)fnum;
+ } else {
+ if ((fnum = cli_open(cli, pipe_name, O_CREAT|O_RDWR, DENY_NONE)) == -1) {
+ DEBUG(0,("cli_nt_session_open: cli_open failed on pipe %s to machine %s. Error was %s\n",
+ pipe_name, cli->desthost, cli_errstr(cli)));
+ return False;
+ }
+
+ cli->nt_pipe_fnum = (uint16)fnum;
+
+ /**************** Set Named Pipe State ***************/
+ if (!rpc_pipe_set_hnd_state(cli, pipe_name, 0x4300)) {
+ DEBUG(0,("cli_nt_session_open: pipe hnd state failed. Error was %s\n",
+ cli_errstr(cli)));
+ cli_close(cli, cli->nt_pipe_fnum);
+ return False;
+ }
+ }
+
+ /******************* bind request on pipe *****************/
+
+ if (!rpc_pipe_bind(cli, pipe_name, global_myname)) {
+ DEBUG(0,("cli_nt_session_open: rpc bind failed. Error was %s\n",
+ cli_errstr(cli)));
+ cli_close(cli, cli->nt_pipe_fnum);
+ return False;
+ }
+
+ /*
+ * Setup the remote server name prefixed by \ and the machine account name.
+ */
+
+ fstrcpy(cli->srv_name_slash, "\\\\");
+ fstrcat(cli->srv_name_slash, cli->desthost);
+ strupper(cli->srv_name_slash);
+
+ fstrcpy(cli->clnt_name_slash, "\\\\");
+ fstrcat(cli->clnt_name_slash, global_myname);
+ strupper(cli->clnt_name_slash);
+
+ fstrcpy(cli->mach_acct, global_myname);
+ fstrcat(cli->mach_acct, "$");
+ strupper(cli->mach_acct);
+
+ return True;
+}
+
+/****************************************************************************
+close the session
+****************************************************************************/
+
+void cli_nt_session_close(struct cli_state *cli)
+{
+ cli_close(cli, cli->nt_pipe_fnum);
+ cli->nt_pipe_fnum = 0;
+}
diff --git a/source/rpc_client/cli_reg.c b/source/rpc_client/cli_reg.c
new file mode 100644
index 00000000000..cc433ab566b
--- /dev/null
+++ b/source/rpc_client/cli_reg.c
@@ -0,0 +1,1072 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 1997-1998.
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * 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"
+
+/****************************************************************************
+do a REG Open Policy
+****************************************************************************/
+BOOL do_reg_connect(struct cli_state *cli, char *full_keyname, char *key_name,
+ POLICY_HND *reg_hnd)
+{
+ BOOL res = True;
+ uint32 reg_type = 0;
+
+ if (full_keyname == NULL)
+ return False;
+
+ ZERO_STRUCTP(reg_hnd);
+
+ /*
+ * open registry receive a policy handle
+ */
+
+ if (!reg_split_key(full_keyname, &reg_type, key_name)) {
+ DEBUG(0,("do_reg_connect: unrecognised key name %s\n", full_keyname));
+ return False;
+ }
+
+ switch (reg_type) {
+ case HKEY_LOCAL_MACHINE:
+ res = res ? do_reg_open_hklm(cli, 0x84E0, 0x02000000, reg_hnd) : False;
+ break;
+
+ case HKEY_USERS:
+ res = res ? do_reg_open_hku(cli, 0x84E0, 0x02000000, reg_hnd) : False;
+ break;
+
+ default:
+ DEBUG(0,("do_reg_connect: unrecognised hive key\n"));
+ return False;
+ }
+
+ return res;
+}
+
+/****************************************************************************
+do a REG Open Policy
+****************************************************************************/
+BOOL do_reg_open_hklm(struct cli_state *cli, uint16 unknown_0, uint32 level,
+ POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_OPEN_HKLM q_o;
+ REG_R_OPEN_HKLM r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_OPEN_HKLM */
+
+ DEBUG(4,("REG Open HKLM\n"));
+
+ init_reg_q_open_hklm(&q_o, unknown_0, level);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_open_hklm("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_OPEN_HKLM, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_open_hklm("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_OPEN_HKLM: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* ok, at last: we're happy. return the policy handle */
+ *hnd = r_o.pol;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Open HKU
+****************************************************************************/
+BOOL do_reg_open_hku(struct cli_state *cli, uint16 unknown_0, uint32 level,
+ POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_OPEN_HKU q_o;
+ REG_R_OPEN_HKU r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_OPEN_HKU */
+
+ DEBUG(4,("REG Open HKU\n"));
+
+ init_reg_q_open_hku(&q_o, unknown_0, level);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_open_hku("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, REG_OPEN_HKU, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_open_hku("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_OPEN_HKU: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* ok, at last: we're happy. return the policy handle */
+ *hnd = r_o.pol;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Unknown 0xB command. sent after a create key or create value.
+this might be some sort of "sync" or "refresh" command, sent after
+modification of the registry...
+****************************************************************************/
+BOOL do_reg_flush_key(struct cli_state *cli, POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_FLUSH_KEY q_o;
+ REG_R_FLUSH_KEY r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_FLUSH_KEY */
+
+ DEBUG(4,("REG Unknown 0xB\n"));
+
+ init_reg_q_flush_key(&q_o, hnd);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_flush_key("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_FLUSH_KEY, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_flush_key("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_FLUSH_KEY: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Query Key
+****************************************************************************/
+BOOL do_reg_query_key(struct cli_state *cli, POLICY_HND *hnd,
+ char *class, uint32 *class_len,
+ uint32 *num_subkeys, uint32 *max_subkeylen,
+ uint32 *max_subkeysize, uint32 *num_values,
+ uint32 *max_valnamelen, uint32 *max_valbufsize,
+ uint32 *sec_desc, NTTIME *mod_time)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_QUERY_KEY q_o;
+ REG_R_QUERY_KEY r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_QUERY_KEY */
+
+ DEBUG(4,("REG Query Key\n"));
+
+ init_reg_q_query_key(&q_o, hnd, *class_len);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_query_key("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_QUERY_KEY, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_query_key("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_QUERY_KEY: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ *class_len = r_o.hdr_class.uni_max_len;
+ rpcstr_pull(class, &r_o.uni_class, -1, -1, 0);
+ *num_subkeys = r_o.num_subkeys ;
+ *max_subkeylen = r_o.max_subkeylen ;
+ *max_subkeysize = r_o.max_subkeysize;
+ *num_values = r_o.num_values ;
+ *max_valnamelen = r_o.max_valnamelen;
+ *max_valbufsize = r_o.max_valbufsize;
+ *sec_desc = r_o.sec_desc ;
+ *mod_time = r_o.mod_time ;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Unknown 1A
+****************************************************************************/
+BOOL do_reg_unknown_1a(struct cli_state *cli, POLICY_HND *hnd, uint32 *unk)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_UNK_1A q_o;
+ REG_R_UNK_1A r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_UNKNOWN_1A */
+
+ DEBUG(4,("REG Unknown 1a\n"));
+
+ init_reg_q_unk_1a(&q_o, hnd);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_unk_1a("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, REG_UNK_1A, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_unk_1a("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_UNK_1A: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ (*unk) = r_o.unknown;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Query Info
+****************************************************************************/
+BOOL do_reg_query_info(struct cli_state *cli, POLICY_HND *hnd,
+ char *key_value, uint32* key_type)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_INFO q_o;
+ REG_R_INFO r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_INFO */
+
+ DEBUG(4,("REG Query Info\n"));
+
+ init_reg_q_info(&q_o, hnd, "ProductType");
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_info("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_INFO, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_info("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if ( r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_INFO: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /*fstrcpy(key_value, dos_buffer2_to_str(r_o.uni_val));*/
+ rpcstr_pull(key_value, r_o.uni_val->buffer, sizeof(fstring), r_o.uni_val->buf_len, 0);
+ *key_type = r_o.type;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Set Key Security
+****************************************************************************/
+BOOL do_reg_set_key_sec(struct cli_state *cli, POLICY_HND *hnd, SEC_DESC_BUF *sec_desc_buf)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_SET_KEY_SEC q_o;
+ REG_R_SET_KEY_SEC r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_SET_KEY_SEC */
+
+ DEBUG(4,("REG Set Key security.\n"));
+
+ init_reg_q_set_key_sec(&q_o, hnd, sec_desc_buf);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_set_key_sec("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_SET_KEY_SEC, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_set_key_sec("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Query Key Security
+****************************************************************************/
+
+BOOL do_reg_get_key_sec(struct cli_state *cli, POLICY_HND *hnd, uint32 *sec_buf_size, SEC_DESC_BUF **ppsec_desc_buf)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_GET_KEY_SEC q_o;
+ REG_R_GET_KEY_SEC r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_GET_KEY_SEC */
+
+ DEBUG(4,("REG query key security. buf_size: %d\n", *sec_buf_size));
+
+ init_reg_q_get_key_sec(&q_o, hnd, *sec_buf_size, NULL);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_get_key_sec("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_GET_KEY_SEC, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_get_key_sec("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status == 0x0000007a) {
+ /*
+ * get the maximum buffer size: it was too small
+ */
+ (*sec_buf_size) = r_o.hdr_sec.buf_max_len;
+ DEBUG(5,("sec_buf_size too small. use %d\n", *sec_buf_size));
+ } else if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_GET_KEY_SEC: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ } else {
+ (*sec_buf_size) = r_o.data->len;
+ *ppsec_desc_buf = r_o.data;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Delete Value
+****************************************************************************/
+BOOL do_reg_delete_val(struct cli_state *cli, POLICY_HND *hnd, char *val_name)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_DELETE_VALUE q_o;
+ REG_R_DELETE_VALUE r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_DELETE_VALUE */
+
+ DEBUG(4,("REG Delete Value: %s\n", val_name));
+
+ init_reg_q_delete_val(&q_o, hnd, val_name);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_delete_val("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, REG_DELETE_VALUE, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_delete_val("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_DELETE_VALUE: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Delete Key
+****************************************************************************/
+BOOL do_reg_delete_key(struct cli_state *cli, POLICY_HND *hnd, char *key_name)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_DELETE_KEY q_o;
+ REG_R_DELETE_KEY r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_DELETE_KEY */
+
+ DEBUG(4,("REG Delete Key: %s\n", key_name));
+
+ init_reg_q_delete_key(&q_o, hnd, key_name);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_delete_key("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_DELETE_KEY, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_delete_key("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_DELETE_KEY: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Create Key
+****************************************************************************/
+BOOL do_reg_create_key(struct cli_state *cli, POLICY_HND *hnd,
+ char *key_name, char *key_class,
+ SEC_ACCESS *sam_access,
+ POLICY_HND *key)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_CREATE_KEY q_o;
+ REG_R_CREATE_KEY r_o;
+ SEC_DESC *sec = NULL;
+ SEC_DESC_BUF *sec_buf = NULL;
+ size_t sec_len;
+
+ ZERO_STRUCT(q_o);
+
+ if (hnd == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api REG_CREATE_KEY */
+
+ DEBUG(4,("REG Create Key: %s %s 0x%08x\n", key_name, key_class,
+ sam_access != NULL ? sam_access->mask : 0));
+
+ if((sec = make_sec_desc( cli->mem_ctx, 1, NULL, NULL, NULL, NULL, &sec_len)) == NULL) {
+ DEBUG(0,("make_sec_desc : malloc fail.\n"));
+ return False;
+ }
+
+ DEBUG(10,("make_sec_desc: len = %d\n", (int)sec_len));
+
+ if((sec_buf = make_sec_desc_buf( cli->mem_ctx, (int)sec_len, sec)) == NULL) {
+ DEBUG(0,("make_sec_desc : malloc fail (1)\n"));
+ return False;
+ }
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ init_reg_q_create_key(&q_o, hnd, key_name, key_class, sam_access, sec_buf);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_create_key("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, REG_CREATE_KEY, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_create_key("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_CREATE_KEY: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ *key = r_o.key_pol;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Enum Key
+****************************************************************************/
+BOOL do_reg_enum_key(struct cli_state *cli, POLICY_HND *hnd,
+ int key_index, char *key_name,
+ uint32 *unk_1, uint32 *unk_2,
+ time_t *mod_time)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_ENUM_KEY q_o;
+ REG_R_ENUM_KEY r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_ENUM_KEY */
+
+ DEBUG(4,("REG Enum Key\n"));
+
+ init_reg_q_enum_key(&q_o, hnd, key_index);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_enum_key("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_ENUM_KEY, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_enum_key("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_ENUM_KEY: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ (*unk_1) = r_o.unknown_1;
+ (*unk_2) = r_o.unknown_2;
+ rpcstr_pull(key_name, r_o.key_name.str.buffer, -1, -1, 0);
+ (*mod_time) = nt_time_to_unix(&r_o.time);
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Create Value
+****************************************************************************/
+BOOL do_reg_create_val(struct cli_state *cli, POLICY_HND *hnd,
+ char *val_name, uint32 type, BUFFER3 *data)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_CREATE_VALUE q_o;
+ REG_R_CREATE_VALUE r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_CREATE_VALUE */
+
+ DEBUG(4,("REG Create Value: %s\n", val_name));
+
+ init_reg_q_create_val(&q_o, hnd, val_name, type, data);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_create_val("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_CREATE_VALUE, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_create_val("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_CREATE_VALUE: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Enum Value
+****************************************************************************/
+BOOL do_reg_enum_val(struct cli_state *cli, POLICY_HND *hnd,
+ int val_index, int max_valnamelen, int max_valbufsize,
+ fstring val_name,
+ uint32 *val_type, BUFFER2 *value)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_ENUM_VALUE q_o;
+ REG_R_ENUM_VALUE r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_ENUM_VALUE */
+
+ DEBUG(4,("REG Enum Value\n"));
+
+ init_reg_q_enum_val(&q_o, hnd, val_index, max_valnamelen, max_valbufsize);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_enum_val("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_ENUM_VALUE, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+ r_o.buf_value = value;
+
+ if(!reg_io_r_enum_val("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_ENUM_VALUE: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ (*val_type) = r_o.type;
+ rpcstr_pull(val_name, &r_o.uni_name, -1, -1, 0);
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Open Key
+****************************************************************************/
+BOOL do_reg_open_entry(struct cli_state *cli, POLICY_HND *hnd,
+ char *key_name, uint32 unk_0,
+ POLICY_HND *key_hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_OPEN_ENTRY q_o;
+ REG_R_OPEN_ENTRY r_o;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api REG_OPEN_ENTRY */
+
+ DEBUG(4,("REG Open Entry\n"));
+
+ init_reg_q_open_entry(&q_o, hnd, key_name, unk_0);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_open_entry("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_OPEN_ENTRY, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_o);
+
+ if(!reg_io_r_open_entry("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_OPEN_ENTRY: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ *key_hnd = r_o.pol;
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
+
+/****************************************************************************
+do a REG Close
+****************************************************************************/
+BOOL do_reg_close(struct cli_state *cli, POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ REG_Q_CLOSE q_c;
+ REG_R_CLOSE r_c;
+
+ if (hnd == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api REG_CLOSE */
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("REG Close\n"));
+
+ /* store the parameters */
+ init_reg_q_close(&q_c, hnd);
+
+ /* turn parameters into data stream */
+ if(!reg_io_q_close("", &q_c, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, REG_CLOSE, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ ZERO_STRUCT(r_c);
+
+ if(!reg_io_r_close("", &r_c, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_c.status != 0) {
+ /* report error code */
+ DEBUG(0,("REG_CLOSE: %s\n", get_nt_error_msg(r_c.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* check that the returned policy handle is all zeros */
+
+ if (IVAL(&r_c.pol.data1,0) || IVAL(&r_c.pol.data2,0) || SVAL(&r_c.pol.data3,0) ||
+ SVAL(&r_c.pol.data4,0) || IVAL(r_c.pol.data5,0) || IVAL(r_c.pol.data5,4) ) {
+ prs_mem_free(&rbuf);
+ DEBUG(0,("REG_CLOSE: non-zero handle returned\n"));
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
diff --git a/source/rpc_client/cli_samr.c b/source/rpc_client/cli_samr.c
new file mode 100644
index 00000000000..ff8a3a3a67a
--- /dev/null
+++ b/source/rpc_client/cli_samr.c
@@ -0,0 +1,838 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Jeremy Allison 1999.
+
+ 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"
+
+/****************************************************************************
+do a SAMR query user groups
+****************************************************************************/
+BOOL get_samr_query_usergroups(struct cli_state *cli,
+ POLICY_HND *pol_open_domain, uint32 user_rid,
+ uint32 *num_groups, DOM_GID *gid)
+{
+ POLICY_HND pol_open_user;
+ if (pol_open_domain == NULL || num_groups == NULL || gid == NULL)
+ return False;
+
+ /* send open domain (on user sid) */
+ if (!do_samr_open_user(cli,
+ pol_open_domain,
+ 0x02011b, user_rid,
+ &pol_open_user))
+ {
+ return False;
+ }
+
+ /* send user groups query */
+ if (!do_samr_query_usergroups(cli,
+ &pol_open_user,
+ num_groups, gid))
+ {
+ DEBUG(5,("do_samr_query_usergroups: error in query user groups\n"));
+ }
+
+ return do_samr_close(cli, &pol_open_user);
+}
+
+#if 0
+/* DOES NOT COMPILE WITH THE NEW SAMR PARSE CODE. JRA. */
+
+/****************************************************************************
+do a SAMR query user info
+****************************************************************************/
+BOOL get_samr_query_userinfo(struct cli_state *cli,
+ POLICY_HND *pol_open_domain,
+ uint32 info_level,
+ uint32 user_rid, SAM_USER_INFO_21 *usr)
+{
+ POLICY_HND pol_open_user;
+ if (pol_open_domain == NULL || usr == NULL)
+ return False;
+
+ memset((char *)usr, '\0', sizeof(*usr));
+
+ /* send open domain (on user sid) */
+ if (!do_samr_open_user(cli,
+ pol_open_domain,
+ 0x02011b, user_rid,
+ &pol_open_user))
+ {
+ return False;
+ }
+
+ /* send user info query */
+ if (!do_samr_query_userinfo(cli,
+ &pol_open_user,
+ info_level, (void*)usr))
+ {
+ DEBUG(5,("do_samr_query_userinfo: error in query user info, level 0x%x\n",
+ info_level));
+ }
+
+ return do_samr_close(cli, &pol_open_user);
+}
+#endif
+
+/****************************************************************************
+do a SAMR change user password command
+****************************************************************************/
+BOOL do_samr_chgpasswd_user(struct cli_state *cli,
+ char *srv_name, char *user_name,
+ char nt_newpass[516], uchar nt_oldhash[16],
+ char lm_newpass[516], uchar lm_oldhash[16])
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_CHGPASSWD_USER q_e;
+ SAMR_R_CHGPASSWD_USER r_e;
+
+ /* create and send a MSRPC command with api SAMR_CHGPASSWD_USER */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Change User Password. server:%s username:%s\n",
+ srv_name, user_name));
+
+ init_samr_q_chgpasswd_user(&q_e, srv_name, user_name,
+ nt_newpass, nt_oldhash,
+ lm_newpass, lm_oldhash);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_chgpasswd_user("", &q_e, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_CHGPASSWD_USER, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_chgpasswd_user("", &r_e, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_e.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_CHGPASSWD_USER: %s\n", get_nt_error_msg(r_e.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+#if 0
+
+/* CURRENTLY THIS DOESN'T COMPILE AND IS NOT USED ANYWHERE. JRA. */
+
+/****************************************************************************
+do a SAMR unknown 0x38 command
+****************************************************************************/
+BOOL do_samr_unknown_38(struct cli_state *cli, char *srv_name)
+{
+ prs_struct data;
+ prs_struct rdata;
+
+ SAMR_Q_UNKNOWN_38 q_e;
+ SAMR_R_UNKNOWN_38 r_e;
+
+ /* create and send a MSRPC command with api SAMR_ENUM_DOM_USERS */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Unknown 38 server:%s\n", srv_name));
+
+ init_samr_q_unknown_38(&q_e, srv_name);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_unknown_38("", &q_e, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_UNKNOWN_38, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_unknown_38("", &r_e, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_e.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_UNKNOWN_38: %s\n", get_nt_error_msg(r_e.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+#endif
+
+/****************************************************************************
+do a SAMR unknown 0x8 command
+****************************************************************************/
+BOOL do_samr_query_dom_info(struct cli_state *cli,
+ POLICY_HND *domain_pol, uint16 switch_value)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_QUERY_DOMAIN_INFO q_e;
+ SAMR_R_QUERY_DOMAIN_INFO r_e;
+
+ if (domain_pol == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_ENUM_DOM_USERS */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Unknown 8 switch:%d\n", switch_value));
+
+ /* store the parameters */
+ init_samr_q_query_dom_info(&q_e, domain_pol, switch_value);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_query_dom_info("", &q_e, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_QUERY_DOMAIN_INFO, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_query_dom_info("", &r_e, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_e.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_QUERY_DOMAIN_INFO: %s\n", get_nt_error_msg(r_e.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+#if 0
+
+/* CURRENTLY DOESN'T COMPILE WITH THE NEW SAMR PARSE CODE. JRA */
+
+/****************************************************************************
+do a SAMR enumerate users
+****************************************************************************/
+BOOL do_samr_enum_dom_users(struct cli_state *cli,
+ POLICY_HND *pol, uint16 num_entries, uint16 unk_0,
+ uint16 acb_mask, uint16 unk_1, uint32 size,
+ struct acct_info **sam,
+ int *num_sam_users)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_ENUM_DOM_USERS q_e;
+ SAMR_R_ENUM_DOM_USERS r_e;
+ int i;
+ int name_idx = 0;
+
+ if (pol == NULL || num_sam_users == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_ENUM_DOM_USERS */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Enum SAM DB max size:%x\n", size));
+
+ /* store the parameters */
+ init_samr_q_enum_dom_users(&q_e, pol,
+ num_entries, unk_0,
+ acb_mask, unk_1, size);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_enum_dom_users("", &q_e, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_ENUM_DOM_USERS, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_enum_dom_users("", &r_e, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_e.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_ENUM_DOM_USERS: %s\n", get_nt_error_msg(r_e.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ *num_sam_users = r_e.num_entries2;
+ if (*num_sam_users > MAX_SAM_ENTRIES) {
+ *num_sam_users = MAX_SAM_ENTRIES;
+ DEBUG(2,("do_samr_enum_dom_users: sam user entries limited to %d\n",
+ *num_sam_users));
+ }
+
+ *sam = (struct acct_info*) malloc(sizeof(struct acct_info) * (*num_sam_users));
+
+ if ((*sam) == NULL)
+ *num_sam_users = 0;
+
+ for (i = 0; i < *num_sam_users; i++) {
+ (*sam)[i].smb_userid = r_e.sam[i].rid;
+ if (r_e.sam[i].hdr_name.buffer) {
+ char *acct_name = dos_unistrn2(r_e.uni_acct_name[name_idx].buffer,
+ r_e.uni_acct_name[name_idx].uni_str_len);
+ fstrcpy((*sam)[i].acct_name, acct_name);
+ name_idx++;
+ } else {
+ memset((char *)(*sam)[i].acct_name, '\0', sizeof((*sam)[i].acct_name));
+ }
+
+ DEBUG(5,("do_samr_enum_dom_users: idx: %4d rid: %8x acct: %s\n",
+ i, (*sam)[i].smb_userid, (*sam)[i].acct_name));
+ }
+
+ prs_mem_free(&rdata );
+
+ return True;
+}
+#endif
+
+/****************************************************************************
+do a SAMR Connect
+****************************************************************************/
+BOOL do_samr_connect(struct cli_state *cli,
+ char *srv_name, uint32 unknown_0,
+ POLICY_HND *connect_pol)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_CONNECT q_o;
+ SAMR_R_CONNECT r_o;
+
+ if (srv_name == NULL || connect_pol == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_CONNECT */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Open Policy server:%s undoc value:%x\n",
+ srv_name, unknown_0));
+
+ /* store the parameters */
+ init_samr_q_connect(&q_o, srv_name, unknown_0);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_connect("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_CONNECT, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_connect("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_CONNECT: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ memcpy(connect_pol, &r_o.connect_pol, sizeof(r_o.connect_pol));
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+/****************************************************************************
+do a SAMR Open User
+****************************************************************************/
+BOOL do_samr_open_user(struct cli_state *cli,
+ POLICY_HND *pol, uint32 unk_0, uint32 rid,
+ POLICY_HND *user_pol)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_OPEN_USER q_o;
+ SAMR_R_OPEN_USER r_o;
+
+ if (pol == NULL || user_pol == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_OPEN_USER */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Open User. unk_0: %08x RID:%x\n",
+ unk_0, rid));
+
+ /* store the parameters */
+ init_samr_q_open_user(&q_o, pol, unk_0, rid);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_open_user("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_OPEN_USER, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_open_user("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_OPEN_USER: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ memcpy(user_pol, &r_o.user_pol, sizeof(r_o.user_pol));
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+/****************************************************************************
+do a SAMR Open Domain
+****************************************************************************/
+BOOL do_samr_open_domain(struct cli_state *cli,
+ POLICY_HND *connect_pol, uint32 rid, DOM_SID *sid,
+ POLICY_HND *domain_pol)
+{
+ prs_struct data;
+ prs_struct rdata;
+ pstring sid_str;
+ SAMR_Q_OPEN_DOMAIN q_o;
+ SAMR_R_OPEN_DOMAIN r_o;
+
+ if (connect_pol == NULL || sid == NULL || domain_pol == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_OPEN_DOMAIN */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ sid_to_string(sid_str, sid);
+ DEBUG(4,("SAMR Open Domain. SID:%s RID:%x\n", sid_str, rid));
+
+ /* store the parameters */
+ init_samr_q_open_domain(&q_o, connect_pol, rid, sid);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_open_domain("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_OPEN_DOMAIN, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_open_domain("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_OPEN_DOMAIN: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ memcpy(domain_pol, &r_o.domain_pol, sizeof(r_o.domain_pol));
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+#if 0
+
+/* CURRENTLY DOES NOT COMPILE AND IS NOT USED ANYWHERE. JRA. */
+
+/****************************************************************************
+do a SAMR Query Unknown 12
+****************************************************************************/
+BOOL do_samr_query_unknown_12(struct cli_state *cli,
+ POLICY_HND *pol, uint32 rid, uint32 num_gids, uint32 *gids,
+ uint32 *num_aliases,
+ fstring als_names [MAX_LOOKUP_SIDS],
+ uint32 num_als_users[MAX_LOOKUP_SIDS])
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_LOOKUP_RIDS q_o;
+ SAMR_R_LOOKUP_RIDS r_o;
+
+ if (pol == NULL || rid == 0 || num_gids == 0 || gids == NULL ||
+ num_aliases == NULL || als_names == NULL || num_als_users == NULL )
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_UNKNOWN_12 */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Query Unknown 12.\n"));
+
+ /* store the parameters */
+ init_samr_q_lookup_rids(&q_o, pol, rid, num_gids, gids);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_lookup_rids("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_LOOKUP_RIDS, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_lookup_rids("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_UNKNOWN_12: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.ptr_aliases != 0 && r_o.ptr_als_usrs != 0 &&
+ r_o.num_als_usrs1 == r_o.num_aliases1) {
+ int i;
+
+ *num_aliases = r_o.num_aliases1;
+
+ for (i = 0; i < r_o.num_aliases1; i++) {
+ fstrcpy(als_names[i], dos_unistrn2(r_o.uni_als_name[i].buffer,
+ r_o.uni_als_name[i].uni_str_len));
+ }
+ for (i = 0; i < r_o.num_als_usrs1; i++) {
+ num_als_users[i] = r_o.num_als_usrs[i];
+ }
+ } else if (r_o.ptr_aliases == 0 && r_o.ptr_als_usrs == 0) {
+ *num_aliases = 0;
+ } else {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+#endif
+
+/****************************************************************************
+do a SAMR Query User Groups
+****************************************************************************/
+BOOL do_samr_query_usergroups(struct cli_state *cli,
+ POLICY_HND *pol, uint32 *num_groups, DOM_GID *gid)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_QUERY_USERGROUPS q_o;
+ SAMR_R_QUERY_USERGROUPS r_o;
+
+ if (pol == NULL || gid == NULL || num_groups == 0)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_QUERY_USERGROUPS */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Query User Groups.\n"));
+
+ /* store the parameters */
+ init_samr_q_query_usergroups(&q_o, pol);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_query_usergroups("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_QUERY_USERGROUPS, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ /* get user info */
+ r_o.gid = gid;
+
+ if(!samr_io_r_query_usergroups("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_QUERY_USERGROUPS: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ *num_groups = r_o.num_entries;
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+#if 0
+
+/* CURRENTLY DOES NOT COMPILE WITH THE NEW SAMR PARSE CODE. JRA */
+
+/****************************************************************************
+do a SAMR Query User Info
+****************************************************************************/
+BOOL do_samr_query_userinfo(struct cli_state *cli,
+ POLICY_HND *pol, uint16 switch_value, void* usr)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_QUERY_USERINFO q_o;
+ SAMR_R_QUERY_USERINFO r_o;
+
+ if (pol == NULL || usr == NULL || switch_value == 0)
+ return False;
+
+ /* create and send a MSRPC command with api SAMR_QUERY_USERINFO */
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SAMR Query User Info. level: %d\n", switch_value));
+
+ /* store the parameters */
+ init_samr_q_query_userinfo(&q_o, pol, switch_value);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_query_userinfo("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_QUERY_USERINFO, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ /* get user info */
+ r_o.info.id = usr;
+
+ if(!samr_io_r_query_userinfo("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_R_QUERY_USERINFO: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.switch_value != switch_value) {
+ DEBUG(0,("SAMR_R_QUERY_USERINFO: received incorrect level %d\n",
+ r_o.switch_value));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.ptr == 0) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+#endif
+
+/****************************************************************************
+do a SAMR Close
+****************************************************************************/
+BOOL do_samr_close(struct cli_state *cli, POLICY_HND *hnd)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SAMR_Q_CLOSE_HND q_c;
+ SAMR_R_CLOSE_HND r_c;
+
+ if (hnd == NULL)
+ return False;
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SAMR_CLOSE_HND */
+
+ DEBUG(4,("SAMR Close\n"));
+
+ /* store the parameters */
+ init_samr_q_close_hnd(&q_c, hnd);
+
+ /* turn parameters into data stream */
+ if(!samr_io_q_close_hnd("", &q_c, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SAMR_CLOSE_HND, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!samr_io_r_close_hnd("", &r_c, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_c.status != 0) {
+ /* report error code */
+ DEBUG(0,("SAMR_CLOSE_HND: %s\n", get_nt_error_msg(r_c.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* check that the returned policy handle is all zeros */
+
+ if (IVAL(&r_c.pol.data1,0) || IVAL(&r_c.pol.data2,0) || SVAL(&r_c.pol.data3,0) ||
+ SVAL(&r_c.pol.data4,0) || IVAL(r_c.pol.data5,0) || IVAL(r_c.pol.data5,4) ) {
+ DEBUG(0,("SAMR_CLOSE_HND: non-zero handle returned\n"));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
diff --git a/source/rpc_client/cli_spoolss.c b/source/rpc_client/cli_spoolss.c
new file mode 100644
index 00000000000..39655519f99
--- /dev/null
+++ b/source/rpc_client/cli_spoolss.c
@@ -0,0 +1,818 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ * Copyright (C) Paul Ashton 1997-2000,
+ * Copyright (C) Jean Francois Micouleau 1998-2000,
+ *
+ * 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"
+#include "rpc_parse.h"
+#include "nterr.h"
+
+/****************************************************************************
+do a SPOOLSS Enum Printer Drivers
+****************************************************************************/
+uint32 spoolss_enum_printerdrivers(const char *srv_name, const char *environment,
+ uint32 level, NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ENUMPRINTERDRIVERS q_o;
+ SPOOL_R_ENUMPRINTERDRIVERS r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ struct cli_connection *con = NULL;
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUM_PRINTERS */
+
+ DEBUG(5,("SPOOLSS Enum Printer Drivers (Server: %s Environment: %s level: %d)\n",
+ srv_name, environment, level));
+
+ make_spoolss_q_enumprinterdrivers(&q_o, srv_name, environment,
+ level, buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_enumprinterdrivers("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_ENUMPRINTERDRIVERS, &buf, &rbuf))
+ {
+ prs_mem_free(&buf);
+ ZERO_STRUCT(r_o);
+
+ prs_switch_type(&buffer->prs, UNMARSHALL);
+ prs_set_offset(&buffer->prs, 0);
+ r_o.buffer=buffer;
+
+ if(spoolss_io_r_enumprinterdrivers("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_ENUMPRINTERDRIVERS: %s\n", get_nt_error_msg(r_o.status)));
+ }
+ *needed=r_o.needed;
+ *returned=r_o.returned;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ cli_connection_unlink(con);
+
+ return r_o.status;
+}
+
+/****************************************************************************
+do a SPOOLSS Enum Printers
+****************************************************************************/
+uint32 spoolss_enum_printers(uint32 flags, fstring srv_name, uint32 level,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ENUMPRINTERS q_o;
+ SPOOL_R_ENUMPRINTERS r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ struct cli_connection *con = NULL;
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUM_PRINTERS */
+
+ DEBUG(5,("SPOOLSS Enum Printers (Server: %s level: %d)\n", srv_name, level));
+
+ make_spoolss_q_enumprinters(&q_o, flags, "", level, buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_enumprinters("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_ENUMPRINTERS, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+
+ prs_switch_type(&buffer->prs, UNMARSHALL);
+ prs_set_offset(&buffer->prs, 0);
+ r_o.buffer=buffer;
+
+ if(new_spoolss_io_r_enumprinters("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ /* report error code */
+ DEBUG(3,("SPOOLSS_ENUMPRINTERS: %s\n", get_nt_error_msg(r_o.status)));
+ }
+
+ *needed=r_o.needed;
+ *returned=r_o.returned;
+ }
+
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ cli_connection_unlink(con);
+
+ return r_o.status;
+}
+
+/****************************************************************************
+do a SPOOLSS Enum Ports
+****************************************************************************/
+uint32 spoolss_enum_ports(fstring srv_name, uint32 level,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ENUMPORTS q_o;
+ SPOOL_R_ENUMPORTS r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ struct cli_connection *con = NULL;
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUMPORTS */
+
+ DEBUG(5,("SPOOLSS Enum Ports (Server: %s level: %d)\n", srv_name, level));
+
+ make_spoolss_q_enumports(&q_o, "", level, buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_enumports("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_ENUMPORTS, &buf, &rbuf))
+ {
+ prs_mem_free(&buf );
+ ZERO_STRUCT(r_o);
+
+ prs_switch_type(&buffer->prs, UNMARSHALL);
+ prs_set_offset(&buffer->prs, 0);
+ r_o.buffer=buffer;
+
+ if(new_spoolss_io_r_enumports("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_ENUMPORTS: %s\n", get_nt_error_msg(r_o.status)));
+ }
+
+ *needed=r_o.needed;
+ *returned=r_o.returned;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ cli_connection_unlink(con);
+
+ return r_o.status;
+}
+
+/****************************************************************************
+do a SPOOLSS Enum Jobs
+****************************************************************************/
+uint32 spoolss_enum_jobs(const POLICY_HND *hnd, uint32 firstjob, uint32 numofjobs,
+ uint32 level, NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed, uint32 *returned)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ENUMJOBS q_o;
+ SPOOL_R_ENUMJOBS r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ if (hnd == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUMJOBS */
+
+ DEBUG(5,("SPOOLSS Enum Jobs level: %d)\n", level));
+
+ make_spoolss_q_enumjobs(&q_o, hnd, firstjob, numofjobs, level, buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_enumjobs("", &q_o, &buf, 0) &&
+ rpc_hnd_pipe_req(hnd, SPOOLSS_ENUMJOBS, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+ prs_mem_free(&buf );
+
+ r_o.buffer=buffer;
+
+ if(spoolss_io_r_enumjobs("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_ENUMJOBS: %s\n", get_nt_error_msg(r_o.status)));
+ }
+ *needed=r_o.needed;
+ *returned=r_o.returned;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return r_o.status;
+}
+
+/***************************************************************************
+do a SPOOLSS Enum printer datas
+****************************************************************************/
+uint32 spoolss_enum_printerdata(const POLICY_HND *hnd, uint32 idx,
+ uint32 *valuelen, uint16 *value, uint32 *rvaluelen,
+ uint32 *type, uint32 *datalen, uint8 *data,
+ uint32 *rdatalen)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ENUMPRINTERDATA q_o;
+ SPOOL_R_ENUMPRINTERDATA r_o;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if (hnd == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_jobs: talloc_init failed!\n"));
+ return False;
+ }
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUMPRINTERDATA*/
+
+ DEBUG(4,("SPOOLSS Enum Printer data\n"));
+
+ make_spoolss_q_enumprinterdata(&q_o, hnd, idx, *valuelen, *datalen);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_enumprinterdata("", &q_o, &buf, 0) &&
+ rpc_hnd_pipe_req(hnd, SPOOLSS_ENUMPRINTERDATA, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+ prs_mem_free(&buf );
+
+ r_o.data=data;
+ r_o.value=value;
+
+ if(spoolss_io_r_enumprinterdata("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_ENUMPRINTERDATA: %s\n", get_nt_error_msg(r_o.status)));
+ }
+
+ *valuelen=r_o.valuesize;
+ *rvaluelen=r_o.realvaluesize;
+ *type=r_o.type;
+ *datalen=r_o.datasize;
+ *rdatalen=r_o.realdatasize;
+
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return r_o.status;
+}
+
+/****************************************************************************
+do a SPOOLSS Enum printer datas
+****************************************************************************/
+uint32 spoolss_getprinter(const POLICY_HND *hnd, uint32 level,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_GETPRINTER q_o;
+ SPOOL_R_GETPRINTER r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ if (hnd == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUMJOBS */
+
+ DEBUG(5,("SPOOLSS Enum Printer data)\n"));
+
+ make_spoolss_q_getprinter(&q_o, hnd, level, buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_getprinter("", &q_o, &buf, 0) &&
+ rpc_hnd_pipe_req(hnd, SPOOLSS_GETPRINTER, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+ prs_mem_free(&buf );
+
+ prs_switch_type(&buffer->prs, UNMARSHALL);
+ prs_set_offset(&buffer->prs, 0);
+ r_o.buffer=buffer;
+
+ if(!spoolss_io_r_getprinter("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_GETPRINTER: %s\n", get_nt_error_msg(r_o.status)));
+ }
+ *needed=r_o.needed;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return r_o.status;
+}
+
+/****************************************************************************
+do a SPOOLSS Enum printer driver
+****************************************************************************/
+uint32 spoolss_getprinterdriver(const POLICY_HND *hnd,
+ const char *environment, uint32 level,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_GETPRINTERDRIVER2 q_o;
+ SPOOL_R_GETPRINTERDRIVER2 r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ if (hnd == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUMJOBS */
+
+ DEBUG(5,("SPOOLSS Enum Printer driver)\n"));
+
+ make_spoolss_q_getprinterdriver2(&q_o, hnd, environment, level, 2, 0, buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_getprinterdriver2("", &q_o, &buf, 0) &&
+ rpc_hnd_pipe_req(hnd, SPOOLSS_GETPRINTERDRIVER2, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+ prs_mem_free(&buf );
+
+ prs_switch_type(&buffer->prs, UNMARSHALL);
+ prs_set_offset(&buffer->prs, 0);
+ r_o.buffer=buffer;
+
+ if(spoolss_io_r_getprinterdriver2("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_GETPRINTERDRIVER2: %s\n", get_nt_error_msg(r_o.status)));
+ }
+
+ *needed=r_o.needed;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return r_o.status;
+}
+
+
+
+/****************************************************************************
+do a SPOOLSS Open Printer Ex
+****************************************************************************/
+BOOL spoolss_open_printer_ex( const char *printername,
+ const char *datatype, uint32 access_required,
+ const char *station, const char *username,
+ POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_OPEN_PRINTER_EX q_o;
+ BOOL valid_pol = False;
+ fstring srv_name;
+ char *s = NULL;
+ struct cli_connection *con = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ memset(srv_name, 0, sizeof(srv_name));
+ fstrcpy(srv_name, printername);
+
+ s = strchr_m(&srv_name[2], '\\');
+ if (s != NULL)
+ *s = '\0';
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return False;
+
+ if (hnd == NULL)
+ return False;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_jobs: talloc_init failed!\n"));
+ return False;
+ }
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_OPENPRINTEREX */
+
+ DEBUG(5,("SPOOLSS Open Printer Ex\n"));
+
+ make_spoolss_q_open_printer_ex(&q_o, printername, datatype,
+ access_required, station, username);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_open_printer_ex("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_OPENPRINTEREX, &buf, &rbuf))
+ {
+ SPOOL_R_OPEN_PRINTER_EX r_o;
+ BOOL p = True;
+
+ spoolss_io_r_open_printer_ex("", &r_o, &rbuf, 0);
+
+ if (prs_offset(&rbuf)!= 0 && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(3,("SPOOLSS_OPENPRINTEREX: %s\n", get_nt_error_msg(r_o.status)));
+ p = False;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. return the policy handle */
+ *hnd = r_o.handle;
+
+ /* associate the handle returned with the current
+ state of the clienjt connection */
+ valid_pol = RpcHndList_set_connection(hnd, con);
+
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return valid_pol;
+}
+
+/****************************************************************************
+ do a SPOOLSS AddPrinterEx()
+ **ALWAYS** uses as PRINTER_INFO level 2 struct
+****************************************************************************/
+BOOL spoolss_addprinterex(POLICY_HND *hnd, const char* srv_name, PRINTER_INFO_2 *info2)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ADDPRINTEREX q_o;
+ SPOOL_R_ADDPRINTEREX r_o;
+ struct cli_connection *con = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ fstring the_client_name;
+ BOOL valid_pol = True;
+
+
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return NT_STATUS_ACCESS_DENIED;
+
+ if (hnd == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("spoolss_addprinterex: talloc_init() failed!\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUMPORTS */
+ DEBUG(5,("SPOOLSS Add Printer Ex (Server: %s)\n", srv_name));
+
+ fstrcpy(the_client_name, "\\\\");
+ fstrcat(the_client_name, con->pCli_state->desthost);
+ strupper(the_client_name);
+
+
+ make_spoolss_q_addprinterex(mem_ctx, &q_o, srv_name, the_client_name,
+ /* "Administrator", */
+ con->pCli_state->user_name,
+ 2, info2);
+
+ /* turn parameters into data stream and send the request */
+ if (spoolss_io_q_addprinterex("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_ADDPRINTEREX, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+
+ if(spoolss_io_r_addprinterex("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ /* report error code */
+ DEBUG(3,("SPOOLSS_ADDPRINTEREX: %s\n", get_nt_error_msg(r_o.status)));
+ valid_pol = False;
+ }
+ }
+
+ if (valid_pol)
+ {
+ /* ok, at last: we're happy. return the policy handle */
+ copy_policy_hnd( hnd, &r_o.handle);
+
+ /* associate the handle returned with the current
+ state of the clienjt connection */
+ RpcHndList_set_connection(hnd, con);
+ }
+ }
+
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return valid_pol;
+}
+
+/****************************************************************************
+do a SPOOL Close
+****************************************************************************/
+BOOL spoolss_closeprinter(POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_CLOSEPRINTER q_c;
+ BOOL valid_close = False;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if (hnd == NULL)
+ return False;
+
+ /* create and send a MSRPC command with api SPOOLSS_CLOSEPRINTER */
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_jobs: talloc_init failed!\n"));
+ return False;
+ }
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ DEBUG(4,("SPOOL Close Printer\n"));
+
+ /* store the parameters */
+ make_spoolss_q_closeprinter(&q_c, hnd);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_closeprinter("", &q_c, &buf, 0) &&
+ rpc_hnd_pipe_req(hnd, SPOOLSS_CLOSEPRINTER, &buf, &rbuf))
+ {
+ SPOOL_R_CLOSEPRINTER r_c;
+
+ spoolss_io_r_closeprinter("", &r_c, &rbuf, 0);
+
+ if (prs_offset(&rbuf)!=0 && r_c.status != 0)
+ {
+ /* report error code */
+ DEBUG(3,("SPOOL_CLOSEPRINTER: %s\n", get_nt_error_msg(r_c.status)));
+ }
+ else
+ valid_close = True;
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ /* disassociate with the cli_connection */
+ RpcHndList_del_connection(hnd);
+
+ return valid_close;
+}
+
+/****************************************************************************
+do a SPOOLSS Get printer datas
+****************************************************************************/
+uint32 spoolss_getprinterdata(const POLICY_HND *hnd, const UNISTR2 *valuename,
+ uint32 in_size,
+ uint32 *type,
+ uint32 *out_size,
+ uint8 *data,
+ uint32 *needed)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_GETPRINTERDATA q_o;
+ SPOOL_R_GETPRINTERDATA r_o;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if (hnd == NULL)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_jobs: talloc_init failed!\n"));
+ return False;
+ }
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_GETPRINTERDATA */
+
+ DEBUG(5,("SPOOLSS Get Printer data)\n"));
+
+ make_spoolss_q_getprinterdata(&q_o, hnd,(UNISTR2 *)valuename, in_size);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_getprinterdata("", &q_o, &buf, 0) &&
+ rpc_hnd_pipe_req(hnd, SPOOLSS_GETPRINTERDATA, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+ prs_mem_free(&buf );
+
+ r_o.data=data;
+
+ if(spoolss_io_r_getprinterdata("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_GETPRINTERDATA: %s\n", get_nt_error_msg(r_o.status)));
+ }
+
+ *type=r_o.type;
+ *out_size=r_o.size;
+ *needed=r_o.needed;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return r_o.status;
+}
+
+/****************************************************************************
+do a SPOOLSS Get Printer Driver Direcotry
+****************************************************************************/
+uint32 spoolss_getprinterdriverdir(fstring srv_name, fstring env_name, uint32 level,
+ NEW_BUFFER *buffer, uint32 offered,
+ uint32 *needed)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_GETPRINTERDRIVERDIR q_o;
+ SPOOL_R_GETPRINTERDRIVERDIR r_o;
+ TALLOC_CTX *ctx = prs_get_mem_context(&buffer->prs);
+
+ struct cli_connection *con = NULL;
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, ctx, MARSHALL);
+ prs_init(&rbuf, 0, ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SPOOLSS_ENUM_PRINTERS */
+
+ DEBUG(5,("SPOOLSS GetPrinterDriverDir (Server: %s Env: %s level: %d)\n",
+ srv_name, env_name, level));
+
+ make_spoolss_q_getprinterdriverdir(&q_o, srv_name, env_name, level,
+ buffer, offered);
+
+ /* turn parameters into data stream */
+ if (spoolss_io_q_getprinterdriverdir("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_GETPRINTERDRIVERDIRECTORY, &buf, &rbuf))
+ {
+ prs_mem_free(&buf );
+ ZERO_STRUCT(r_o);
+
+ prs_switch_type(&buffer->prs, UNMARSHALL);
+ prs_set_offset(&buffer->prs, 0);
+ r_o.buffer=buffer;
+
+ if(spoolss_io_r_getprinterdriverdir("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ DEBUG(3,("SPOOLSS_GETPRINTERDRIVERDIRECTORY: %s\n", get_nt_error_msg(r_o.status)));
+ }
+
+ *needed=r_o.needed;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ cli_connection_unlink(con);
+
+ return r_o.status;
+}
+
+/******************************************************************************
+ AddPrinterDriver()
+ *****************************************************************************/
+uint32 spoolss_addprinterdriver(const char *srv_name, uint32 level, PRINTER_DRIVER_CTR *info)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ SPOOL_Q_ADDPRINTERDRIVER q_o;
+ SPOOL_R_ADDPRINTERDRIVER r_o;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct cli_connection *con = NULL;
+
+ if (!cli_connection_init(srv_name, PIPE_SPOOLSS, &con))
+ return False;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_jobs: talloc_init failed!\n"));
+ return False;
+ }
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* make the ADDPRINTERDRIVER PDU */
+ make_spoolss_q_addprinterdriver(mem_ctx, &q_o, srv_name, level, info);
+
+ /* turn the data into an io stream */
+ if (spoolss_io_q_addprinterdriver("", &q_o, &buf, 0) &&
+ rpc_con_pipe_req(con, SPOOLSS_ADDPRINTERDRIVER, &buf, &rbuf))
+ {
+ ZERO_STRUCT(r_o);
+
+ if(spoolss_io_r_addprinterdriver("", &r_o, &rbuf, 0))
+ {
+ if (r_o.status != NT_STATUS_OK)
+ {
+ /* report error code */
+ DEBUG(3,("SPOOLSS_ADDPRINTERDRIVER: %s\n", get_nt_error_msg(r_o.status)));
+ }
+ }
+ }
+
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return r_o.status;
+
+}
diff --git a/source/rpc_client/cli_spoolss_notify.c b/source/rpc_client/cli_spoolss_notify.c
new file mode 100644
index 00000000000..2f89e200d21
--- /dev/null
+++ b/source/rpc_client/cli_spoolss_notify.c
@@ -0,0 +1,293 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Jean Francois Micouleau 1998-2000,
+ *
+ * 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"
+#include "rpc_parse.h"
+#include "nterr.h"
+
+extern pstring global_myname;
+
+/*********************************************************
+ Disconnect from the client machine.
+**********************************************************/
+BOOL spoolss_disconnect_from_client( struct cli_state *cli)
+{
+ cli_nt_session_close(cli);
+ cli_ulogoff(cli);
+ cli_shutdown(cli);
+
+ return True;
+}
+
+
+/*********************************************************
+ Connect to the client machine.
+**********************************************************/
+
+BOOL spoolss_connect_to_client( struct cli_state *cli, char *remote_machine)
+{
+ ZERO_STRUCTP(cli);
+ if(cli_initialise(cli) == NULL) {
+ DEBUG(0,("connect_to_client: unable to initialize client connection.\n"));
+ return False;
+ }
+
+ if(!resolve_name( remote_machine, &cli->dest_ip, 0x20)) {
+ DEBUG(0,("connect_to_client: Can't resolve address for %s\n", remote_machine));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (ismyip(cli->dest_ip)) {
+ DEBUG(0,("connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!cli_connect(cli, remote_machine, &cli->dest_ip)) {
+ DEBUG(0,("connect_to_client: unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!attempt_netbios_session_request(cli, global_myname, remote_machine, &cli->dest_ip)) {
+ DEBUG(0,("connect_to_client: machine %s rejected the NetBIOS session request. Error was %s\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ cli->protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(cli)) {
+ DEBUG(0,("connect_to_client: machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (cli->protocol != PROTOCOL_NT1) {
+ DEBUG(0,("connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ /*
+ * Do an anonymous session setup.
+ */
+
+ if (!cli_session_setup(cli, "", "", 0, "", 0, "")) {
+ DEBUG(0,("connect_to_client: machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!(cli->sec_mode & 1)) {
+ DEBUG(0,("connect_to_client: machine %s isn't in user level security mode\n", remote_machine));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
+ DEBUG(0,("connect_to_client: machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ /*
+ * Ok - we have an anonymous connection to the IPC$ share.
+ * Now start the NT Domain stuff :-).
+ */
+
+ if(cli_nt_session_open(cli, PIPE_SPOOLSS) == False) {
+ DEBUG(0,("connect_to_client: unable to open the domain client session to machine %s. Error was : %s.\n", remote_machine, cli_errstr(cli)));
+ cli_nt_session_close(cli);
+ cli_ulogoff(cli);
+ cli_shutdown(cli);
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ do a reply open printer
+****************************************************************************/
+
+BOOL cli_spoolss_reply_open_printer(struct cli_state *cli, char *printer, uint32 localprinter, uint32 type, WERROR *status, POLICY_HND *handle)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+
+ SPOOL_Q_REPLYOPENPRINTER q_s;
+ SPOOL_R_REPLYOPENPRINTER r_s;
+
+ prs_init(&buf, 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL );
+
+ /* create and send a MSRPC command with api SPOOLSS_REPLYOPENPRINTER */
+/*
+ DEBUG(4,("cli_spoolss_reply_open_printer: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan_type, global_myname,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
+*/
+ /* store the parameters */
+ make_spoolss_q_replyopenprinter(&q_s, printer, localprinter, type);
+
+ /* turn parameters into data stream */
+ if(!spoolss_io_q_replyopenprinter("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_spoolss_reply_open_printer: Error : failed to marshall NET_Q_SRV_PWSET struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SPOOLSS_REPLYOPENPRINTER, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ /* turn data stream into parameters*/
+ if(!spoolss_io_r_replyopenprinter("", &r_s, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ memcpy(handle, &r_s.handle, sizeof(r_s.handle));
+ *status=r_s.status;
+
+ return True;
+}
+
+/***************************************************************************
+ do a reply open printer
+****************************************************************************/
+
+BOOL cli_spoolss_reply_rrpcn(struct cli_state *cli, POLICY_HND *handle,
+ uint32 change_low, uint32 change_high, WERROR *status)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+
+ SPOOL_Q_REPLY_RRPCN q_s;
+ SPOOL_R_REPLY_RRPCN r_s;
+
+ prs_init(&buf, 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL );
+
+ /* create and send a MSRPC command with api */
+/*
+ DEBUG(4,("cli_spoolss_reply_open_printer: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan_type, global_myname,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
+*/
+ /* store the parameters */
+ make_spoolss_q_reply_rrpcn(&q_s, handle, change_low, change_high);
+
+ /* turn parameters into data stream */
+ if(!spoolss_io_q_reply_rrpcn("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_spoolss_reply_rrpcn: Error : failed to marshall SPOOL_Q_REPLY_RRPCN struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SPOOLSS_RRPCN, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ /* turn data stream into parameters*/
+ if(!spoolss_io_r_reply_rrpcn("", &r_s, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ *status=r_s.status;
+
+ return True;
+}
+
+/***************************************************************************
+ do a reply open printer
+****************************************************************************/
+
+BOOL cli_spoolss_reply_close_printer(struct cli_state *cli, POLICY_HND *handle,
+ WERROR *status)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+
+ SPOOL_Q_REPLYCLOSEPRINTER q_s;
+ SPOOL_R_REPLYCLOSEPRINTER r_s;
+
+ prs_init(&buf, 1024, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL );
+
+ /* create and send a MSRPC command with api */
+/*
+ DEBUG(4,("cli_spoolss_reply_open_printer: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan_type, global_myname,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
+*/
+ /* store the parameters */
+ make_spoolss_q_reply_closeprinter(&q_s, handle);
+
+ /* turn parameters into data stream */
+ if(!spoolss_io_q_replycloseprinter("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_spoolss_reply_close_printer: Error : failed to marshall SPOOL_Q_REPLY_CLOSEPRINTER struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SPOOLSS_REPLYCLOSEPRINTER, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ /* turn data stream into parameters*/
+ if(!spoolss_io_r_replycloseprinter("", &r_s, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ *status=r_s.status;
+
+ return True;
+}
diff --git a/source/rpc_client/cli_srvsvc.c b/source/rpc_client/cli_srvsvc.c
new file mode 100644
index 00000000000..50f2eeb1583
--- /dev/null
+++ b/source/rpc_client/cli_srvsvc.c
@@ -0,0 +1,401 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * 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"
+
+/****************************************************************************
+do a server net conn enum
+****************************************************************************/
+BOOL do_srv_net_srv_conn_enum(struct cli_state *cli,
+ char *server_name, char *qual_name,
+ uint32 switch_value, SRV_CONN_INFO_CTR *ctr,
+ uint32 preferred_len,
+ ENUM_HND *hnd)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SRV_Q_NET_CONN_ENUM q_o;
+ SRV_R_NET_CONN_ENUM r_o;
+
+ if (server_name == NULL || ctr == NULL || preferred_len == 0)
+ return False;
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SRV_NETCONNENUM */
+
+ DEBUG(4,("SRV Net Server Connection Enum(%s, %s), level %d, enum:%8x\n",
+ server_name, qual_name, switch_value, get_enum_hnd(hnd)));
+
+ ctr->switch_value = switch_value;
+ ctr->ptr_conn_ctr = 1;
+ ctr->conn.info0.num_entries_read = 0;
+ ctr->conn.info0.ptr_conn_info = 1;
+
+ /* store the parameters */
+ init_srv_q_net_conn_enum(&q_o, server_name, qual_name,
+ switch_value, ctr,
+ preferred_len,
+ hnd);
+
+ /* turn parameters into data stream */
+ if(!srv_io_q_net_conn_enum("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if(!rpc_api_pipe_req(cli, SRV_NETCONNENUM, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ r_o.ctr = ctr;
+
+ if(!srv_io_r_net_conn_enum("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SRV_CONN_ENUM: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.ctr->switch_value != switch_value) {
+ /* different switch levels. oops. */
+ DEBUG(0,("SRV_R_NET_SRV_CONN_ENUM: info class %d does not match request %d\n",
+ r_o.ctr->switch_value, switch_value));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+/****************************************************************************
+do a server net sess enum
+****************************************************************************/
+
+BOOL do_srv_net_srv_sess_enum(struct cli_state *cli,
+ char *server_name, char *qual_name,
+ uint32 switch_value, SRV_SESS_INFO_CTR *ctr,
+ uint32 preferred_len,
+ ENUM_HND *hnd)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SRV_Q_NET_SESS_ENUM q_o;
+ SRV_R_NET_SESS_ENUM r_o;
+
+ if (server_name == NULL || ctr == NULL || preferred_len == 0)
+ return False;
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SRV_NETSESSENUM */
+
+ DEBUG(4,("SRV Net Session Enum (%s), level %d, enum:%8x\n",
+ server_name, switch_value, get_enum_hnd(hnd)));
+
+ ctr->switch_value = switch_value;
+ ctr->ptr_sess_ctr = 1;
+ ctr->sess.info0.num_entries_read = 0;
+ ctr->sess.info0.ptr_sess_info = 1;
+
+ /* store the parameters */
+ init_srv_q_net_sess_enum(&q_o, server_name, qual_name,
+ switch_value, ctr,
+ preferred_len,
+ hnd);
+
+ /* turn parameters into data stream */
+ if(!srv_io_q_net_sess_enum("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SRV_NETSESSENUM, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ r_o.ctr = ctr;
+
+ if(!srv_io_r_net_sess_enum("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SRV_SESS_ENUM: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.ctr->switch_value != switch_value) {
+ /* different switch levels. oops. */
+ DEBUG(0,("SRV_R_NET_SRV_SESS_ENUM: info class %d does not match request %d\n",
+ r_o.ctr->switch_value, switch_value));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+/****************************************************************************
+do a server net share enum
+****************************************************************************/
+BOOL do_srv_net_srv_share_enum(struct cli_state *cli,
+ char *server_name,
+ uint32 switch_value, SRV_R_NET_SHARE_ENUM *r_o,
+ uint32 preferred_len, ENUM_HND *hnd)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SRV_Q_NET_SHARE_ENUM q_o;
+
+ if (server_name == NULL || preferred_len == 0)
+ return False;
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SRV_NETSHAREENUM */
+
+ DEBUG(4,("SRV Get Share Info (%s), level %d, enum:%8x\n",
+ server_name, switch_value, get_enum_hnd(hnd)));
+
+ /* store the parameters */
+ init_srv_q_net_share_enum(&q_o, server_name, switch_value,
+ preferred_len, hnd);
+
+ /* turn parameters into data stream */
+ if(!srv_io_q_net_share_enum("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SRV_NETSHAREENUM, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ if(!srv_io_r_net_share_enum("", r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o->status != 0) {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SHARE_ENUM: %s\n", get_nt_error_msg(r_o->status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o->ctr.switch_value != switch_value) {
+ /* different switch levels. oops. */
+ DEBUG(0,("SRV_R_NET_SHARE_ENUM: info class %d does not match request %d\n",
+ r_o->ctr.switch_value, switch_value));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+/****************************************************************************
+do a server net file enum
+****************************************************************************/
+
+BOOL do_srv_net_srv_file_enum(struct cli_state *cli,
+ char *server_name, char *qual_name,
+ uint32 switch_value, SRV_FILE_INFO_CTR *ctr,
+ uint32 preferred_len,
+ ENUM_HND *hnd)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SRV_Q_NET_FILE_ENUM q_o;
+ SRV_R_NET_FILE_ENUM r_o;
+
+ if (server_name == NULL || ctr == NULL || preferred_len == 0)
+ return False;
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SRV_NETFILEENUM */
+
+ DEBUG(4,("SRV Get File Info (%s), level %d, enum:%8x\n",
+ server_name, switch_value, get_enum_hnd(hnd)));
+
+ q_o.file_level = switch_value;
+
+ ctr->switch_value = switch_value;
+ ctr->ptr_file_ctr = 1;
+ ctr->file.info3.num_entries_read = 0;
+ ctr->file.info3.ptr_file_info = 1;
+
+ /* store the parameters */
+ init_srv_q_net_file_enum(&q_o, server_name, qual_name,
+ switch_value, ctr,
+ preferred_len,
+ hnd);
+
+ /* turn parameters into data stream */
+ if(!srv_io_q_net_file_enum("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SRV_NETFILEENUM, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ r_o.ctr = ctr;
+
+ if(!srv_io_r_net_file_enum("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_FILE_ENUM: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.ctr->switch_value != switch_value) {
+ /* different switch levels. oops. */
+ DEBUG(0,("SRV_R_NET_FILE_ENUM: info class %d does not match request %d\n",
+ r_o.ctr->switch_value, switch_value));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
+
+/****************************************************************************
+do a server get info
+****************************************************************************/
+BOOL do_srv_net_srv_get_info(struct cli_state *cli,
+ char *server_name, uint32 switch_value, SRV_INFO_CTR *ctr)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SRV_Q_NET_SRV_GET_INFO q_o;
+ SRV_R_NET_SRV_GET_INFO r_o;
+
+ if (server_name == NULL || switch_value == 0 || ctr == NULL)
+ return False;
+
+ prs_init(&data, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api SRV_NET_SRV_GET_INFO */
+
+ DEBUG(4,("SRV Get Server Info (%s), level %d\n", server_name, switch_value));
+
+ /* store the parameters */
+ init_srv_q_net_srv_get_info(&q_o, server_name, switch_value);
+
+ /* turn parameters into data stream */
+ if(!srv_io_q_net_srv_get_info("", &q_o, &data, 0)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SRV_NET_SRV_GET_INFO, &data, &rdata)) {
+ prs_mem_free(&data);
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&data);
+
+ r_o.ctr = ctr;
+
+ if(!srv_io_r_net_srv_get_info("", &r_o, &rdata, 0)) {
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SRV_GET_INFO: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ if (r_o.ctr->switch_value != q_o.switch_value) {
+ /* different switch levels. oops. */
+ DEBUG(0,("SRV_R_NET_SRV_GET_INFO: info class %d does not match request %d\n",
+ r_o.ctr->switch_value, q_o.switch_value));
+ prs_mem_free(&rdata);
+ return False;
+ }
+
+ prs_mem_free(&rdata);
+
+ return True;
+}
diff --git a/source/rpc_client/cli_trust.c b/source/rpc_client/cli_trust.c
new file mode 100644
index 00000000000..5322c4756fc
--- /dev/null
+++ b/source/rpc_client/cli_trust.c
@@ -0,0 +1,152 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1998.
+ * Copyright (C) Andrew Bartlett 2001.
+ *
+ * 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"
+
+extern pstring global_myname;
+
+/*********************************************************
+ Change the domain password on the PDC.
+**********************************************************/
+
+static NTSTATUS modify_trust_password( char *domain, char *remote_machine,
+ unsigned char orig_trust_passwd_hash[16])
+{
+ struct cli_state *cli;
+ DOM_SID domain_sid;
+ struct in_addr dest_ip;
+ NTSTATUS nt_status;
+
+ /*
+ * Ensure we have the domain SID for this domain.
+ */
+
+ if (!secrets_fetch_domain_sid(domain, &domain_sid)) {
+ DEBUG(0, ("domain_client_validate: unable to fetch domain sid.\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if(!resolve_name( remote_machine, &dest_ip, 0x20)) {
+ DEBUG(0,("modify_trust_password: Can't resolve address for %s\n", remote_machine));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!NT_STATUS_IS_OK(cli_full_connection(&cli, global_myname, remote_machine,
+ &dest_ip, 0,
+ "IPC$", "IPC",
+ "", "",
+ "", 0))) {
+ DEBUG(0,("modify_trust_password: Connection to %s failed!\n", remote_machine));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /*
+ * Ok - we have an anonymous connection to the IPC$ share.
+ * Now start the NT Domain stuff :-).
+ */
+
+ if(cli_nt_session_open(cli, PIPE_NETLOGON) == False) {
+ DEBUG(0,("modify_trust_password: unable to open the domain client session to \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(cli)));
+ cli_nt_session_close(cli);
+ cli_ulogoff(cli);
+ cli_shutdown(cli);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ nt_status = trust_pw_change_and_store_it(cli, cli->mem_ctx,
+ orig_trust_passwd_hash);
+
+ cli_nt_session_close(cli);
+ cli_ulogoff(cli);
+ cli_shutdown(cli);
+ return nt_status;
+}
+
+/************************************************************************
+ Change the trust account password for a domain.
+************************************************************************/
+
+NTSTATUS change_trust_account_password( char *domain, char *remote_machine_list)
+{
+ fstring remote_machine;
+ unsigned char old_trust_passwd_hash[16];
+ time_t lct;
+ NTSTATUS res = NT_STATUS_UNSUCCESSFUL;
+
+ if(!secrets_fetch_trust_account_password(domain, old_trust_passwd_hash, &lct)) {
+ DEBUG(0,("change_trust_account_password: unable to read the machine \
+account password for domain %s.\n", domain));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ while(remote_machine_list &&
+ next_token(&remote_machine_list, remote_machine,
+ LIST_SEP, sizeof(remote_machine))) {
+ strupper(remote_machine);
+ if(strequal(remote_machine, "*")) {
+
+ /*
+ * We have been asked to dynamcially determine the IP addresses of the PDC.
+ */
+
+ struct in_addr *ip_list = NULL;
+ int count = 0;
+ int i;
+
+ /* Use the PDC *only* for this. */
+ if(!get_dc_list(True, domain, &ip_list, &count))
+ continue;
+
+ /*
+ * Try and connect to the PDC/BDC list in turn as an IP
+ * address used as a string.
+ */
+
+ for(i = 0; i < count; i++) {
+ fstring dc_name;
+ if(!lookup_dc_name(global_myname, domain, &ip_list[i], dc_name))
+ continue;
+ if(NT_STATUS_IS_OK(res = modify_trust_password( domain, dc_name,
+ old_trust_passwd_hash)))
+ break;
+ }
+
+ SAFE_FREE(ip_list);
+
+ } else {
+ res = modify_trust_password( domain, remote_machine,
+ old_trust_passwd_hash);
+ }
+
+ }
+
+ if (!NT_STATUS_IS_OK(res)) {
+ DEBUG(0,("%s : change_trust_account_password: Failed to change password for \
+domain %s.\n", timestring(False), domain));
+ }
+
+ return res;
+}
diff --git a/source/rpc_client/cli_wkssvc.c b/source/rpc_client/cli_wkssvc.c
new file mode 100644
index 00000000000..745542e6513
--- /dev/null
+++ b/source/rpc_client/cli_wkssvc.c
@@ -0,0 +1,85 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1999.
+ *
+ * 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"
+
+/****************************************************************************
+do a WKS Open Policy
+****************************************************************************/
+BOOL do_wks_query_info(struct cli_state *cli,
+ char *server_name, uint32 switch_value,
+ WKS_INFO_100 *wks100)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ WKS_Q_QUERY_INFO q_o;
+ WKS_R_QUERY_INFO r_o;
+
+ if (server_name == 0 || wks100 == NULL)
+ return False;
+
+ prs_init(&buf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL );
+
+ /* create and send a MSRPC command with api WKS_QUERY_INFO */
+
+ DEBUG(4,("WKS Query Info\n"));
+
+ /* store the parameters */
+ init_wks_q_query_info(&q_o, server_name, switch_value);
+
+ /* turn parameters into data stream */
+ if(!wks_io_q_query_info("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, WKS_QUERY_INFO, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ r_o.wks100 = wks100;
+
+ if(!wks_io_r_query_info("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ if (r_o.status != 0) {
+ /* report error code */
+ DEBUG(0,("WKS_R_QUERY_INFO: %s\n", get_nt_error_msg(r_o.status)));
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ return True;
+}
diff --git a/source/rpc_client/msrpc_spoolss.c b/source/rpc_client/msrpc_spoolss.c
new file mode 100644
index 00000000000..3baec6c569b
--- /dev/null
+++ b/source/rpc_client/msrpc_spoolss.c
@@ -0,0 +1,810 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Jean-Francois Micouleau 1999-2000
+
+ 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"
+#include "nterr.h"
+#include "rpc_parse.h"
+#include "rpcclient.h"
+
+#define DEBUG_TESTING
+
+extern FILE* out_hnd;
+
+extern struct user_creds *usr_creds;
+
+/********************************************************************
+initialize a spoolss NEW_BUFFER.
+********************************************************************/
+void init_buffer(NEW_BUFFER *buffer, uint32 size, TALLOC_CTX *ctx)
+{
+ buffer->ptr = (size!=0)? 1:0;
+ buffer->size=size;
+ buffer->string_at_end=size;
+ prs_init(&buffer->prs, size, ctx, MARSHALL);
+ buffer->struct_start = prs_offset(&buffer->prs);
+}
+
+static void decode_printer_info_0(NEW_BUFFER *buffer, uint32 returned,
+ PRINTER_INFO_0 **info)
+{
+ uint32 i;
+ PRINTER_INFO_0 *inf;
+
+ inf=(PRINTER_INFO_0 *)malloc(returned*sizeof(PRINTER_INFO_0));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_printer_info_0("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_info_1(NEW_BUFFER *buffer, uint32 returned,
+ PRINTER_INFO_1 **info)
+{
+ uint32 i;
+ PRINTER_INFO_1 *inf;
+
+ inf=(PRINTER_INFO_1 *)malloc(returned*sizeof(PRINTER_INFO_1));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_printer_info_1("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_info_2(NEW_BUFFER *buffer, uint32 returned,
+ PRINTER_INFO_2 **info)
+{
+ uint32 i;
+ PRINTER_INFO_2 *inf;
+
+ inf=(PRINTER_INFO_2 *)malloc(returned*sizeof(PRINTER_INFO_2));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ /* a little initialization as we go */
+ inf[i].secdesc = NULL;
+ new_smb_io_printer_info_2("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_info_3(NEW_BUFFER *buffer, uint32 returned,
+ PRINTER_INFO_3 **info)
+{
+ uint32 i;
+ PRINTER_INFO_3 *inf;
+
+ inf=(PRINTER_INFO_3 *)malloc(returned*sizeof(PRINTER_INFO_3));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_printer_info_3("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_driver_1(NEW_BUFFER *buffer, uint32 returned,
+ DRIVER_INFO_1 **info)
+{
+ uint32 i;
+ DRIVER_INFO_1 *inf;
+
+ inf=(DRIVER_INFO_1 *)malloc(returned*sizeof(DRIVER_INFO_1));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_printer_driver_info_1("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_driver_2(NEW_BUFFER *buffer, uint32 returned,
+ DRIVER_INFO_2 **info)
+{
+ uint32 i;
+ DRIVER_INFO_2 *inf;
+
+ inf=(DRIVER_INFO_2 *)malloc(returned*sizeof(DRIVER_INFO_2));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_printer_driver_info_2("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printer_driver_3(NEW_BUFFER *buffer, uint32 returned,
+ DRIVER_INFO_3 **info)
+{
+ uint32 i;
+ DRIVER_INFO_3 *inf;
+
+ inf=(DRIVER_INFO_3 *)malloc(returned*sizeof(DRIVER_INFO_3));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_printer_driver_info_3("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+static void decode_printerdriverdir_info_1(NEW_BUFFER *buffer, DRIVER_DIRECTORY_1 *info)
+{
+/* DRIVER_DIRECTORY_1 *inf;
+
+ inf=(DRIVER_DIRECTORY_1 *)malloc(returned*sizeof(DRIVER_DIRECTORY_1));
+*/
+ prs_set_offset(&buffer->prs, 0);
+
+ new_smb_io_driverdir_1("", buffer, info, 0);
+
+/* *info=inf;*/
+}
+
+/**********************************************************************
+ Decode a PORT_INFO_1 struct from a NEW_BUFFER
+**********************************************************************/
+void decode_port_info_1(NEW_BUFFER *buffer, uint32 returned,
+ PORT_INFO_1 **info)
+{
+ uint32 i;
+ PORT_INFO_1 *inf;
+
+ inf=(PORT_INFO_1*)malloc(returned*sizeof(PORT_INFO_1));
+
+ prs_set_offset(&buffer->prs, 0);
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_port_info_1("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+ Decode a PORT_INFO_2 struct from a NEW_BUFFER
+**********************************************************************/
+void decode_port_info_2(NEW_BUFFER *buffer, uint32 returned,
+ PORT_INFO_2 **info)
+{
+ uint32 i;
+ PORT_INFO_2 *inf;
+
+ inf=(PORT_INFO_2*)malloc(returned*sizeof(PORT_INFO_2));
+
+ prs_set_offset(&buffer->prs, 0);
+
+ for (i=0; i<returned; i++) {
+ new_smb_io_port_info_2("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_enum_printers(char* srv_name, uint32 flags,
+ uint32 level, PRINTER_INFO_CTR ctr)
+{
+ NTSTATUS status;
+ NEW_BUFFER buffer;
+ uint32 needed;
+ uint32 returned;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_printers: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(&buffer, 0, mem_ctx);
+
+ /* send a NULL buffer first */
+ status=spoolss_enum_printers(flags, srv_name, level, &buffer, 0,
+ &needed, &returned);
+
+ if (status==ERROR_INSUFFICIENT_BUFFER) {
+ init_buffer(&buffer, needed, mem_ctx);
+ status=spoolss_enum_printers(flags, srv_name, level, &buffer,
+ needed, &needed, &returned);
+ }
+
+ if (status!=NT_STATUS_OK)
+ {
+ DEBUG(0,("spoolss_enum_printers: %s\n", get_nt_error_msg(status)));
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ /* is there anything to process? */
+ if (returned != 0)
+ {
+ switch (level) {
+ case 1:
+ decode_printer_info_1(&buffer, returned, &(ctr.printers_1));
+ break;
+ case 2:
+ decode_printer_info_2(&buffer, returned, &(ctr.printers_2));
+ break;
+ case 3:
+ decode_printer_info_3(&buffer, returned, &(ctr.printers_3));
+ break;
+ }
+
+ display_printer_info_ctr(out_hnd, ACTION_HEADER , level, returned, ctr);
+ display_printer_info_ctr(out_hnd, ACTION_ENUMERATE, level, returned, ctr);
+ display_printer_info_ctr(out_hnd, ACTION_FOOTER , level, returned, ctr);
+ }
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return True;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_enum_ports(char* srv_name,
+ uint32 level, PORT_INFO_CTR *ctr)
+{
+ NTSTATUS status;
+ NEW_BUFFER buffer;
+ uint32 needed;
+ uint32 returned;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_ports: talloc_init failed!\n"));
+ return False;
+ }
+
+ init_buffer(&buffer, 0, mem_ctx);
+
+ /* send a NULL buffer first */
+ status=spoolss_enum_ports(srv_name, level, &buffer, 0,
+ &needed, &returned);
+
+ if (status==ERROR_INSUFFICIENT_BUFFER) {
+ init_buffer(&buffer, needed, mem_ctx);
+ status=spoolss_enum_ports(srv_name, level, &buffer,
+ needed, &needed, &returned);
+ }
+
+ report(out_hnd, "\tstatus:[%d (%x)]\n", status, status);
+
+ if (status!=NT_STATUS_OK)
+ {
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ /* is there anything to process? */
+ if (returned != 0)
+ {
+ switch (level) {
+ case 1:
+ decode_port_info_1(&buffer, returned, &ctr->port.info_1);
+ break;
+ case 2:
+ decode_port_info_2(&buffer, returned, &ctr->port.info_2);
+ break;
+ default:
+ DEBUG(0,("Unable to decode unknown PORT_INFO_%d\n", level));
+ break;
+ }
+
+ display_port_info_ctr(out_hnd, ACTION_HEADER , level, returned, ctr);
+ display_port_info_ctr(out_hnd, ACTION_ENUMERATE, level, returned, ctr);
+ display_port_info_ctr(out_hnd, ACTION_FOOTER , level, returned, ctr);
+ }
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+
+
+ return True;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+uint32 msrpc_spoolss_getprinterdata( const char* printer_name,
+ const char* station,
+ const char* user_name,
+ const char* value_name,
+ uint32 *type,
+ NEW_BUFFER *buffer,
+ void *fn)
+{
+ POLICY_HND hnd;
+ NTSTATUS status;
+ uint32 needed;
+ uint32 size;
+ char *data;
+ UNISTR2 uni_val_name;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ DEBUG(4,("spoolgetdata - printer: %s server: %s user: %s value: %s\n",
+ printer_name, station, user_name, value_name));
+
+ if(!spoolss_open_printer_ex( printer_name, 0, 0, station, user_name,
+ &hnd))
+ {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ init_unistr2(&uni_val_name, value_name, 0);
+ size = 0;
+ data = NULL;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_getprinterdata: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(buffer, size, mem_ctx);
+
+ status = spoolss_getprinterdata(&hnd, &uni_val_name, size, type, &size,
+ (unsigned char *)data, &needed);
+
+ if (status == ERROR_INSUFFICIENT_BUFFER)
+ {
+ size = needed;
+ init_buffer(buffer, size, mem_ctx);
+ data = prs_data_p(&buffer->prs);
+ status = spoolss_getprinterdata(&hnd, &uni_val_name,
+ size, type, &size,
+ (unsigned char *)data, &needed);
+ }
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ if (status != NT_STATUS_OK)
+ {
+ if (!spoolss_closeprinter(&hnd))
+ return NT_STATUS_ACCESS_DENIED;
+ return status;
+ }
+
+#if 0
+ if (fn != NULL)
+ fn(printer_name, station, level, returned, *ctr);
+#endif
+
+ return status;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_enum_jobs( const char* printer_name,
+ const char* station, const char* user_name,
+ uint32 level,
+ void ***ctr, JOB_INFO_FN(fn))
+{
+ POLICY_HND hnd;
+ NTSTATUS status;
+ NEW_BUFFER buffer;
+ uint32 needed;
+ uint32 returned;
+ uint32 firstjob=0;
+ uint32 numofjobs=0xffff;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ DEBUG(4,("spoolopen - printer: %s server: %s user: %s\n",
+ printer_name, station, user_name));
+
+ if(!spoolss_open_printer_ex( printer_name, 0, 0, station, user_name, &hnd))
+ return False;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enum_jobs: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(&buffer, 0, mem_ctx);
+ status = spoolss_enum_jobs(&hnd, firstjob, numofjobs, level,
+ &buffer, 0, &needed, &returned);
+
+ if (status == ERROR_INSUFFICIENT_BUFFER)
+ {
+ init_buffer(&buffer, needed, mem_ctx);
+ status = spoolss_enum_jobs( &hnd, firstjob, numofjobs, level,
+ &buffer, needed, &needed, &returned);
+ }
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ if (status!=NT_STATUS_OK) {
+ if (!spoolss_closeprinter(&hnd))
+ return False;
+ return False;
+ }
+
+ if (fn != NULL)
+ fn(printer_name, station, level, returned, *ctr);
+
+ return True;
+}
+
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_enum_printerdata( const char* printer_name,
+ const char* station, const char* user_name )
+{
+ POLICY_HND hnd;
+ NTSTATUS status;
+ uint32 idx;
+ uint32 valuelen;
+ uint16 *value;
+ uint32 rvaluelen;
+ uint32 type;
+ uint32 datalen;
+ uint8 *data;
+ uint32 rdatalen;
+ uint32 maxvaluelen;
+ uint32 maxdatalen;
+
+ DEBUG(4,("msrpc_spoolss_enum_printerdata - printer: %s\n", printer_name));
+
+ if(!spoolss_open_printer_ex( printer_name, 0, 0, station, user_name, &hnd))
+ return False;
+
+
+ idx=0;
+ valuelen=0;
+ rvaluelen=0;
+ type=0;
+ datalen=0;
+ rdatalen=0;
+
+ status = spoolss_enum_printerdata(&hnd, idx, &valuelen, value,
+ &rvaluelen, &type, &datalen,
+ data, &rdatalen);
+
+ DEBUG(4,("spoolenum_printerdata - got size: biggest value:[%d], biggest data:[%d]\n", rvaluelen, rdatalen));
+
+ maxvaluelen=valuelen=rvaluelen;
+ maxdatalen=datalen=rdatalen;
+
+ value=(uint16 *)malloc(valuelen*sizeof(uint16));
+ data=(uint8 *)malloc(datalen*sizeof(uint8));
+
+ display_printer_enumdata(out_hnd, ACTION_HEADER, idx, valuelen,
+ value, rvaluelen, type, datalen, data, rdatalen);
+
+ do {
+ valuelen=maxvaluelen;
+ datalen=maxdatalen;
+
+ status = spoolss_enum_printerdata(&hnd, idx, &valuelen,
+ value, &rvaluelen, &type,
+ &datalen, data, &rdatalen);
+ display_printer_enumdata(out_hnd, ACTION_ENUMERATE, idx,
+ valuelen, value, rvaluelen, type,
+ datalen, data, rdatalen);
+ idx++;
+
+ } while (status != 0x0103); /* NO_MORE_ITEMS */
+
+ display_printer_enumdata(out_hnd, ACTION_FOOTER, idx, valuelen,
+ value, rvaluelen, type, datalen, data, rdatalen);
+
+
+ if (status!=NT_STATUS_OK) {
+ /*
+ * the check on this if statement is redundant
+ * since is the status is bad we're going to
+ * return False anyways. The caller will be
+ * unable to determine if there really was a problem
+ * with the spoolss_closeprinter() call --jerry
+ */
+ spoolss_closeprinter(&hnd);
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_getprinter( const char* printer_name, const uint32 level,
+ const char* station, const char* user_name,
+ PRINTER_INFO_CTR ctr)
+{
+ POLICY_HND hnd;
+ NTSTATUS status=0;
+ NEW_BUFFER buffer;
+ uint32 needed=1000;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ DEBUG(4,("spoolenum_getprinter - printer: %s\n", printer_name));
+
+ if(!spoolss_open_printer_ex( printer_name, "", PRINTER_ALL_ACCESS, station, user_name, &hnd))
+ return False;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_getprinter: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(&buffer, needed, mem_ctx);
+
+ status = spoolss_getprinter(&hnd, level, &buffer, needed, &needed);
+
+ if (status==ERROR_INSUFFICIENT_BUFFER) {
+ init_buffer(&buffer, needed, mem_ctx);
+ status = spoolss_getprinter(&hnd, level, &buffer, needed, &needed);
+ }
+
+ report(out_hnd, "\tstatus:[%d (%x)]\n", status, status);
+
+ if (status!=NT_STATUS_OK)
+ {
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ switch (level) {
+ case 0:
+ decode_printer_info_0(&buffer, 1, &(ctr.printers_0));
+ break;
+ case 1:
+ decode_printer_info_1(&buffer, 1, &(ctr.printers_1));
+ break;
+ case 2:
+ decode_printer_info_2(&buffer, 1, &(ctr.printers_2));
+ break;
+ case 3:
+ decode_printer_info_3(&buffer, 1, &(ctr.printers_3));
+ break;
+ }
+
+ display_printer_info_ctr(out_hnd, ACTION_HEADER , level, 1, ctr);
+ display_printer_info_ctr(out_hnd, ACTION_ENUMERATE, level, 1, ctr);
+ display_printer_info_ctr(out_hnd, ACTION_FOOTER , level, 1, ctr);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ if (status!=NT_STATUS_OK) {
+ if (!spoolss_closeprinter(&hnd))
+ return False;
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_getprinterdriver( const char* printer_name,
+ const char *environment, const uint32 level,
+ const char* station, const char* user_name,
+ PRINTER_DRIVER_CTR ctr)
+{
+ POLICY_HND hnd;
+ NTSTATUS status=0;
+ NEW_BUFFER buffer;
+ uint32 needed;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ DEBUG(4,("msrpc_spoolss_enum_getprinterdriver - printer: %s\n", printer_name));
+
+ if(!spoolss_open_printer_ex( printer_name, "", PRINTER_ALL_ACCESS, station, user_name, &hnd))
+ return False;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_getprinterdriver: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(&buffer, 0, mem_ctx);
+
+ status = spoolss_getprinterdriver(&hnd, environment, level, &buffer, 0, &needed);
+
+ if (status==ERROR_INSUFFICIENT_BUFFER) {
+ init_buffer(&buffer, needed, mem_ctx);
+ status = spoolss_getprinterdriver(&hnd, environment, level, &buffer, needed, &needed);
+ }
+
+ /* report(out_hnd, "\tstatus:[%d (%x)]\n", status, status); */
+
+ if (status!=NT_STATUS_OK)
+ {
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ switch (level) {
+ case 1:
+ decode_printer_driver_1(&buffer, 1, &(ctr.info1));
+ break;
+ case 2:
+ decode_printer_driver_2(&buffer, 1, &(ctr.info2));
+ break;
+ case 3:
+ decode_printer_driver_3(&buffer, 1, &(ctr.info3));
+ break;
+ }
+
+ display_printer_driver_ctr(out_hnd, ACTION_HEADER , level, 1, ctr);
+ display_printer_driver_ctr(out_hnd, ACTION_ENUMERATE, level, 1, ctr);
+ display_printer_driver_ctr(out_hnd, ACTION_FOOTER , level, 1, ctr);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ if (status!=NT_STATUS_OK) {
+ if (!spoolss_closeprinter(&hnd))
+ return False;
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_enumprinterdrivers( const char* srv_name,
+ const char *environment, const uint32 level,
+ PRINTER_DRIVER_CTR ctr)
+{
+ NTSTATUS status=0;
+ NEW_BUFFER buffer;
+ uint32 needed;
+ uint32 returned;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ DEBUG(4,("msrpc_spoolss_enum_enumprinterdrivers - server: %s\n", srv_name));
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_enumprinterdrivers: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(&buffer, 0, mem_ctx);
+
+ status = spoolss_enum_printerdrivers(srv_name, environment,
+ level, &buffer, 0, &needed, &returned);
+
+ if (status == ERROR_INSUFFICIENT_BUFFER)
+ {
+ init_buffer(&buffer, needed, mem_ctx);
+ status = spoolss_enum_printerdrivers( srv_name, environment,
+ level, &buffer, needed, &needed, &returned);
+ }
+
+ report(out_hnd, "\tstatus:[%d (%x)]\n", status, status);
+
+ if (status!=NT_STATUS_OK)
+ {
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ switch (level)
+ {
+ case 1:
+ decode_printer_driver_1(&buffer, returned, &(ctr.info1));
+ break;
+ case 2:
+ decode_printer_driver_2(&buffer, returned, &(ctr.info2));
+ break;
+ case 3:
+ decode_printer_driver_3(&buffer, returned, &(ctr.info3));
+ break;
+ }
+
+ display_printer_driver_ctr(out_hnd, ACTION_HEADER , level, returned, ctr);
+ display_printer_driver_ctr(out_hnd, ACTION_ENUMERATE, level, returned, ctr);
+ display_printer_driver_ctr(out_hnd, ACTION_FOOTER , level, returned, ctr);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return True;
+}
+
+/****************************************************************************
+nt spoolss query
+****************************************************************************/
+BOOL msrpc_spoolss_getprinterdriverdir(char* srv_name, char* env_name, uint32 level, DRIVER_DIRECTORY_CTR ctr)
+{
+ NTSTATUS status;
+ NEW_BUFFER buffer;
+ uint32 needed;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if ((mem_ctx=talloc_init()) == NULL)
+ {
+ DEBUG(0,("msrpc_spoolss_getprinterdriverdir: talloc_init failed!\n"));
+ return False;
+ }
+ init_buffer(&buffer, 0, mem_ctx);
+
+ /* send a NULL buffer first */
+ status=spoolss_getprinterdriverdir(srv_name, env_name, level, &buffer, 0, &needed);
+
+ if (status==ERROR_INSUFFICIENT_BUFFER) {
+ init_buffer(&buffer, needed, mem_ctx);
+ status=spoolss_getprinterdriverdir(srv_name, env_name, level, &buffer, needed, &needed);
+ }
+
+ report(out_hnd, "\tstatus:[%d (%x)]\n", status, status);
+
+ if (status!=NT_STATUS_OK)
+ {
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ switch (level) {
+ case 1:
+ decode_printerdriverdir_info_1(&buffer, &(ctr.driver.info_1));
+ break;
+ }
+
+ display_printerdriverdir_info_ctr(out_hnd, ACTION_HEADER , level, ctr);
+ display_printerdriverdir_info_ctr(out_hnd, ACTION_ENUMERATE, level, ctr);
+ display_printerdriverdir_info_ctr(out_hnd, ACTION_FOOTER , level, ctr);
+
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return True;
+}
diff --git a/source/rpc_client/ntclienttrust.c b/source/rpc_client/ntclienttrust.c
new file mode 100644
index 00000000000..9518c6a4857
--- /dev/null
+++ b/source/rpc_client/ntclienttrust.c
@@ -0,0 +1,158 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+
+ 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"
+
+
+/************************************************************************
+ check workstation trust account status
+ ************************************************************************/
+BOOL trust_account_check(struct in_addr dest_ip, char *dest_host,
+ char *hostname, char *domain, fstring mach_acct,
+ fstring new_mach_pwd)
+{
+ pstring tmp;
+ fstring mach_pwd;
+ struct cli_state cli_trust;
+ uchar lm_owf_mach_pwd[16];
+ uchar nt_owf_mach_pwd[16];
+ uchar lm_sess_pwd[24];
+ uchar nt_sess_pwd[24];
+
+ BOOL right_error_code = False;
+ uint8 err_cls;
+ uint32 err_num;
+
+ char *start_mach_pwd;
+ char *change_mach_pwd;
+
+ /* initial machine password */
+ fstrcpy(mach_pwd, hostname);
+ strlower(mach_pwd);
+
+ slprintf(tmp, sizeof(tmp) - 1,"Enter Workstation Trust Account password for [%s].\nDefault is [%s].\nPassword:",
+ mach_acct, mach_pwd);
+
+ start_mach_pwd = (char*)getpass(tmp);
+
+ if (start_mach_pwd[0] != 0)
+ {
+ fstrcpy(mach_pwd, start_mach_pwd);
+ }
+
+ slprintf(tmp, sizeof(tmp)-1, "Enter new Workstation Trust Account password for [%s]\nPress Return to leave at old value.\nNew Password:",
+ mach_acct);
+
+ change_mach_pwd = (char*)getpass(tmp);
+
+ if (change_mach_pwd[0] != 0)
+ {
+ fstrcpy(new_mach_pwd, change_mach_pwd);
+ }
+ else
+ {
+ DEBUG(1,("trust_account_check: password change not requested\n"));
+ change_mach_pwd[0] = 0;
+ }
+
+ DEBUG(1,("initialise cli_trust connection\n"));
+
+ if (!cli_initialise(&cli_trust))
+ {
+ DEBUG(1,("cli_initialise failed for cli_trust\n"));
+ return False;
+ }
+
+ DEBUG(1,("server connect for cli_trust\n"));
+
+ if (!server_connect_init(&cli_trust, hostname, dest_ip, dest_host))
+ {
+ cli_error(&cli_trust, &err_cls, &err_num, NULL);
+ DEBUG(1,("server_connect_init failed (%s)\n", cli_errstr(&cli_trust)));
+
+ cli_shutdown(&cli_trust);
+ return False;
+ }
+
+ DEBUG(1,("server connect cli_trust succeeded\n"));
+
+ nt_lm_owf_gen(mach_pwd, nt_owf_mach_pwd, lm_owf_mach_pwd);
+
+ DEBUG(5,("generating nt owf from initial machine pwd: %s\n", mach_pwd));
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("client cryptkey: "));
+ dump_data(100, cli_trust.cryptkey, sizeof(cli_trust.cryptkey));
+#endif
+
+ SMBencrypt(nt_owf_mach_pwd, cli_trust.cryptkey, nt_sess_pwd);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_owf_mach_pwd: "));
+ dump_data(100, nt_owf_mach_pwd, sizeof(lm_owf_mach_pwd));
+ DEBUG(100,("nt_sess_pwd: "));
+ dump_data(100, nt_sess_pwd, sizeof(nt_sess_pwd));
+#endif
+
+ SMBencrypt(lm_owf_mach_pwd, cli_trust.cryptkey, lm_sess_pwd);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("lm_owf_mach_pwd: "));
+ dump_data(100, lm_owf_mach_pwd, sizeof(lm_owf_mach_pwd));
+ DEBUG(100,("lm_sess_pwd: "));
+ dump_data(100, lm_sess_pwd, sizeof(lm_sess_pwd));
+#endif
+
+ right_error_code = False;
+
+ if (cli_session_setup(&cli_trust, mach_acct,
+ nt_owf_mach_pwd, sizeof(nt_owf_mach_pwd),
+ nt_owf_mach_pwd, sizeof(nt_owf_mach_pwd), domain))
+ {
+ DEBUG(0,("cli_session_setup: NO ERROR! AAAGH! BUG IN SERVER DETECTED!!!\n"));
+ cli_shutdown(&cli_trust);
+
+ return False;
+ }
+
+ cli_error(&cli_trust, &err_cls, &err_num, NULL);
+
+ if (err_num == (0xC0000000 | NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT))
+ {
+ DEBUG(1,("cli_send_tconX: valid workstation trust account exists\n"));
+ right_error_code = True;
+ }
+
+ if (err_num == (0xC0000000 | NT_STATUS_NO_SUCH_USER))
+ {
+ DEBUG(1,("cli_send_tconX: workstation trust account does not exist\n"));
+ right_error_code = False;
+ }
+
+ if (!right_error_code)
+ {
+ DEBUG(1,("server_validate failed (%s)\n", cli_errstr(&cli_trust)));
+ }
+
+ cli_shutdown(&cli_trust);
+ return right_error_code;
+}