diff options
Diffstat (limited to 'source/rpc_client')
-rw-r--r-- | source/rpc_client/cli_login.c | 174 | ||||
-rw-r--r-- | source/rpc_client/cli_netlogon.c | 471 | ||||
-rw-r--r-- | source/rpc_client/cli_pipe.c | 1260 | ||||
-rw-r--r-- | source/rpc_client/cli_reg.c | 1072 | ||||
-rw-r--r-- | source/rpc_client/cli_samr.c | 838 | ||||
-rw-r--r-- | source/rpc_client/cli_spoolss.c | 818 | ||||
-rw-r--r-- | source/rpc_client/cli_spoolss_notify.c | 293 | ||||
-rw-r--r-- | source/rpc_client/cli_srvsvc.c | 401 | ||||
-rw-r--r-- | source/rpc_client/cli_trust.c | 152 | ||||
-rw-r--r-- | source/rpc_client/cli_wkssvc.c | 85 | ||||
-rw-r--r-- | source/rpc_client/msrpc_spoolss.c | 810 | ||||
-rw-r--r-- | source/rpc_client/ntclienttrust.c | 158 |
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, ¤t_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, ¤t_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, ®_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; +} |