X-Git-Url: https://vcs.maemo.org/git/?p=samba;a=blobdiff_plain;f=source%2Flibsmb%2Fclirap.c;fp=source%2Flibsmb%2Fclirap.c;h=6716971fe2cb7fb4c3f6f8e18b5077d38d3a10fb;hp=0000000000000000000000000000000000000000;hb=6bca4ca307d55b6dc888e56cee47aebcddbce786;hpb=7fd70fa738b636089bcc6c961aa3eaa02f20dda2 diff --git a/source/libsmb/clirap.c b/source/libsmb/clirap.c new file mode 100644 index 0000000..6716971 --- /dev/null +++ b/source/libsmb/clirap.c @@ -0,0 +1,921 @@ +/* + Unix SMB/CIFS implementation. + client RAP calls + Copyright (C) Andrew Tridgell 1994-1998 + Copyright (C) Gerald (Jerry) Carter 2004 + + 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" + + +/**************************************************************************** +Call a remote api on an arbitrary pipe. takes param, data and setup buffers. +****************************************************************************/ +BOOL cli_api_pipe(struct cli_state *cli, const char *pipe_name, + uint16 *setup, uint32 setup_count, uint32 max_setup_count, + char *params, uint32 param_count, uint32 max_param_count, + char *data, uint32 data_count, uint32 max_data_count, + char **rparam, uint32 *rparam_count, + char **rdata, uint32 *rdata_count) +{ + cli_send_trans(cli, SMBtrans, + pipe_name, + 0,0, /* fid, flags */ + setup, setup_count, max_setup_count, + params, param_count, max_param_count, + data, data_count, max_data_count); + + return (cli_receive_trans(cli, SMBtrans, + rparam, (unsigned int *)rparam_count, + rdata, (unsigned int *)rdata_count)); +} + +/**************************************************************************** +call a remote api +****************************************************************************/ +BOOL cli_api(struct cli_state *cli, + char *param, int prcnt, int mprcnt, + char *data, int drcnt, int mdrcnt, + char **rparam, unsigned int *rprcnt, + char **rdata, unsigned int *rdrcnt) +{ + cli_send_trans(cli,SMBtrans, + PIPE_LANMAN, /* Name */ + 0,0, /* fid, flags */ + NULL,0,0, /* Setup, length, max */ + param, prcnt, mprcnt, /* Params, length, max */ + data, drcnt, mdrcnt /* Data, length, max */ + ); + + return (cli_receive_trans(cli,SMBtrans, + rparam, rprcnt, + rdata, rdrcnt)); +} + + +/**************************************************************************** +perform a NetWkstaUserLogon +****************************************************************************/ +BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation) +{ + char *rparam = NULL; + char *rdata = NULL; + char *p; + unsigned int rdrcnt,rprcnt; + pstring param; + + memset(param, 0, sizeof(param)); + + /* send a SMBtrans command with api NetWkstaUserLogon */ + p = param; + SSVAL(p,0,132); /* api number */ + p += 2; + pstrcpy_base(p,"OOWb54WrLh",param); + p = skip_string(p,1); + pstrcpy_base(p,"WB21BWDWWDDDDDDDzzzD",param); + p = skip_string(p,1); + SSVAL(p,0,1); + p += 2; + pstrcpy_base(p,user,param); + strupper_m(p); + p += 21; + p++; + p += 15; + p++; + pstrcpy_base(p, workstation, param); + strupper_m(p); + p += 16; + SSVAL(p, 0, CLI_BUFFER_SIZE); + p += 2; + SSVAL(p, 0, CLI_BUFFER_SIZE); + p += 2; + + if (cli_api(cli, + param, PTR_DIFF(p,param),1024, /* param, length, max */ + NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */ + &rparam, &rprcnt, /* return params, return size */ + &rdata, &rdrcnt /* return data, return size */ + )) { + cli->rap_error = rparam? SVAL(rparam,0) : -1; + p = rdata; + + if (cli->rap_error == 0) { + DEBUG(4,("NetWkstaUserLogon success\n")); + cli->privileges = SVAL(p, 24); + /* The cli->eff_name field used to be set here + but it wasn't used anywhere else. */ + } else { + DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error)); + } + } + + SAFE_FREE(rparam); + SAFE_FREE(rdata); + return (cli->rap_error == 0); +} + +/**************************************************************************** +call a NetShareEnum - try and browse available connections on a host +****************************************************************************/ +int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state) +{ + char *rparam = NULL; + char *rdata = NULL; + char *p; + unsigned int rdrcnt,rprcnt; + pstring param; + int count = -1; + + /* now send a SMBtrans command with api RNetShareEnum */ + p = param; + SSVAL(p,0,0); /* api number */ + p += 2; + pstrcpy_base(p,"WrLeh",param); + p = skip_string(p,1); + pstrcpy_base(p,"B13BWz",param); + p = skip_string(p,1); + SSVAL(p,0,1); + /* + * Win2k needs a *smaller* buffer than 0xFFFF here - + * it returns "out of server memory" with 0xFFFF !!! JRA. + */ + SSVAL(p,2,0xFFE0); + p += 4; + + if (cli_api(cli, + param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */ + NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */ + &rparam, &rprcnt, /* return params, length */ + &rdata, &rdrcnt)) /* return data, length */ + { + int res = rparam? SVAL(rparam,0) : -1; + + if (res == 0 || res == ERRmoredata) { + int converter=SVAL(rparam,2); + int i; + + count=SVAL(rparam,4); + p = rdata; + + for (i=0;i (int)rdrcnt) continue; + + stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY; + + pull_ascii_pstring(s1, sname); + pull_ascii_pstring(s2, cmnt); + fn(s1, stype, s2, state); + } + } + } + + SAFE_FREE(rparam); + SAFE_FREE(rdata); + + if (count < 0) { + errno = cli_errno(cli); + } else { + if (!count) { + /* this is a very special case, when the domain master for the + work group isn't part of the work group itself, there is something + wild going on */ + errno = ENOENT; + } + } + + return(count > 0); +} + + + +/**************************************************************************** +Send a SamOEMChangePassword command +****************************************************************************/ +BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password, + const char *old_password) +{ + pstring param; + unsigned char data[532]; + char *p = param; + unsigned char old_pw_hash[16]; + unsigned char new_pw_hash[16]; + unsigned int data_len; + unsigned int param_len = 0; + char *rparam = NULL; + char *rdata = NULL; + unsigned int rprcnt, rdrcnt; + + if (strlen(user) >= sizeof(fstring)-1) { + DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user)); + return False; + } + + SSVAL(p,0,214); /* SamOEMChangePassword command. */ + p += 2; + pstrcpy_base(p, "zsT", param); + p = skip_string(p,1); + pstrcpy_base(p, "B516B16", param); + p = skip_string(p,1); + pstrcpy_base(p,user, param); + p = skip_string(p,1); + SSVAL(p,0,532); + p += 2; + + param_len = PTR_DIFF(p,param); + + /* + * Get the Lanman hash of the old password, we + * use this as the key to make_oem_passwd_hash(). + */ + E_deshash(old_password, old_pw_hash); + + encode_pw_buffer(data, new_password, STR_ASCII); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("make_oem_passwd_hash\n")); + dump_data(100, (char *)data, 516); +#endif + SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516); + + /* + * Now place the old password hash in the data. + */ + E_deshash(new_password, new_pw_hash); + + E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]); + + data_len = 532; + + if (cli_send_trans(cli,SMBtrans, + PIPE_LANMAN, /* name */ + 0,0, /* fid, flags */ + NULL,0,0, /* setup, length, max */ + param,param_len,2, /* param, length, max */ + (char *)data,data_len,0 /* data, length, max */ + ) == False) { + DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n", + user )); + return False; + } + + if (!cli_receive_trans(cli,SMBtrans, + &rparam, &rprcnt, + &rdata, &rdrcnt)) { + DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n", + user )); + return False; + } + + if (rparam) + cli->rap_error = SVAL(rparam,0); + + SAFE_FREE(rparam); + SAFE_FREE(rdata); + + return (cli->rap_error == 0); +} + + +/**************************************************************************** +send a qpathinfo call +****************************************************************************/ +BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, + time_t *c_time, time_t *a_time, time_t *m_time, + SMB_OFF_T *size, uint16 *mode) +{ + unsigned int data_len = 0; + unsigned int param_len = 0; + unsigned int rparam_len, rdata_len; + uint16 setup = TRANSACT2_QPATHINFO; + pstring param; + char *rparam=NULL, *rdata=NULL; + int count=8; + BOOL ret; + time_t (*date_fn)(struct cli_state *, void *); + char *p; + + p = param; + memset(p, 0, 6); + SSVAL(p, 0, SMB_INFO_STANDARD); + p += 6; + p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE); + + param_len = PTR_DIFF(p, param); + + do { + ret = (cli_send_trans(cli, SMBtrans2, + NULL, /* Name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 10, /* param, length, max */ + NULL, data_len, cli->max_xmit /* data, length, max */ + ) && + cli_receive_trans(cli, SMBtrans2, + &rparam, &rparam_len, + &rdata, &rdata_len)); + if (!cli_is_dos_error(cli)) break; + if (!ret) { + /* we need to work around a Win95 bug - sometimes + it gives ERRSRV/ERRerror temprarily */ + uint8 eclass; + uint32 ecode; + cli_dos_error(cli, &eclass, &ecode); + if (eclass != ERRSRV || ecode != ERRerror) break; + smb_msleep(100); + } + } while (count-- && ret==False); + + if (!ret || !rdata || rdata_len < 22) { + return False; + } + + if (cli->win95) { + date_fn = cli_make_unix_date; + } else { + date_fn = cli_make_unix_date2; + } + + if (c_time) { + *c_time = date_fn(cli, rdata+0); + } + if (a_time) { + *a_time = date_fn(cli, rdata+4); + } + if (m_time) { + *m_time = date_fn(cli, rdata+8); + } + if (size) { + *size = IVAL(rdata, 12); + } + if (mode) { + *mode = SVAL(rdata,l1_attrFile); + } + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + return True; +} + + +/**************************************************************************** +send a setpathinfo call +****************************************************************************/ +BOOL cli_setpathinfo(struct cli_state *cli, const char *fname, + time_t c_time, time_t a_time, time_t m_time, uint16 mode) +{ + unsigned int data_len = 0; + unsigned int param_len = 0; + unsigned int rparam_len, rdata_len; + uint16 setup = TRANSACT2_SETPATHINFO; + pstring param; + pstring data; + char *rparam=NULL, *rdata=NULL; + int count=8; + BOOL ret; + void (*date_fn)(struct cli_state *, char *buf,int offset,time_t unixdate); + char *p; + + memset(param, 0, sizeof(param)); + memset(data, 0, sizeof(data)); + + p = param; + + /* Add the information level */ + SSVAL(p, 0, SMB_INFO_STANDARD); + + /* Skip reserved */ + p += 6; + + /* Add the file name */ + p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE); + + param_len = PTR_DIFF(p, param); + + p = data; + + if (cli->win95) { + date_fn = cli_put_dos_date; + } else { + date_fn = cli_put_dos_date2; + } + + /* Add the create, last access, and modification times */ + (*date_fn)(cli, p, 0, c_time); + (*date_fn)(cli, p, 4, a_time); + (*date_fn)(cli, p, 8, m_time); + p += 12; + + /* Skip DataSize and AllocationSize */ + p += 8; + + /* Add attributes */ + SSVAL(p, 0, mode); + p += 2; + + /* Add EA size (none) */ + SIVAL(p, 0, 0); + p += 4; + + data_len = PTR_DIFF(p, data); + + do { + ret = (cli_send_trans(cli, SMBtrans2, + NULL, /* Name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 10, /* param, length, max */ + data, data_len, cli->max_xmit /* data, length, max */ + ) && + cli_receive_trans(cli, SMBtrans2, + &rparam, &rparam_len, + &rdata, &rdata_len)); + if (!cli_is_dos_error(cli)) break; + if (!ret) { + /* we need to work around a Win95 bug - sometimes + it gives ERRSRV/ERRerror temprarily */ + uint8 eclass; + uint32 ecode; + cli_dos_error(cli, &eclass, &ecode); + if (eclass != ERRSRV || ecode != ERRerror) break; + smb_msleep(100); + } + } while (count-- && ret==False); + + if (!ret) { + return False; + } + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + return True; +} + + +/**************************************************************************** +send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level +****************************************************************************/ +BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname, + time_t *c_time, time_t *a_time, time_t *m_time, + time_t *w_time, SMB_OFF_T *size, uint16 *mode, + SMB_INO_T *ino) +{ + unsigned int data_len = 0; + unsigned int param_len = 0; + uint16 setup = TRANSACT2_QPATHINFO; + pstring param; + char *rparam=NULL, *rdata=NULL; + char *p; + + p = param; + memset(p, 0, 6); + SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO); + p += 6; + p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE); + + param_len = PTR_DIFF(p, param); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, /* name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 10, /* param, length, max */ + NULL, data_len, cli->max_xmit /* data, length, max */ + )) { + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return False; + } + + if (!rdata || data_len < 22) { + return False; + } + + if (c_time) { + *c_time = interpret_long_date(rdata+0); + } + if (a_time) { + *a_time = interpret_long_date(rdata+8); + } + if (w_time) { + *w_time = interpret_long_date(rdata+16); + } + if (m_time) { + *m_time = interpret_long_date(rdata+24); + } + if (mode) { + *mode = SVAL(rdata, 32); + } + if (size) { + *size = IVAL2_TO_SMB_BIG_UINT(rdata,48); + } + if (ino) { + *ino = IVAL(rdata, 64); + } + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + return True; +} + + +/**************************************************************************** +send a qfileinfo QUERY_FILE_NAME_INFO call +****************************************************************************/ +BOOL cli_qfilename(struct cli_state *cli, int fnum, + pstring name) +{ + unsigned int data_len = 0; + unsigned int param_len = 0; + uint16 setup = TRANSACT2_QFILEINFO; + pstring param; + char *rparam=NULL, *rdata=NULL; + + param_len = 4; + memset(param, 0, param_len); + SSVAL(param, 0, fnum); + SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, /* name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 2, /* param, length, max */ + NULL, data_len, cli->max_xmit /* data, length, max */ + )) { + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return False; + } + + if (!rdata || data_len < 4) { + return False; + } + + clistr_pull(cli, name, rdata+4, sizeof(pstring), IVAL(rdata, 0), STR_UNICODE); + + return True; +} + + +/**************************************************************************** +send a qfileinfo call +****************************************************************************/ +BOOL cli_qfileinfo(struct cli_state *cli, int fnum, + uint16 *mode, SMB_OFF_T *size, + time_t *c_time, time_t *a_time, time_t *m_time, + time_t *w_time, SMB_INO_T *ino) +{ + unsigned int data_len = 0; + unsigned int param_len = 0; + uint16 setup = TRANSACT2_QFILEINFO; + pstring param; + char *rparam=NULL, *rdata=NULL; + + /* if its a win95 server then fail this - win95 totally screws it + up */ + if (cli->win95) return False; + + param_len = 4; + + memset(param, 0, param_len); + SSVAL(param, 0, fnum); + SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, /* name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 2, /* param, length, max */ + NULL, data_len, cli->max_xmit /* data, length, max */ + )) { + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return False; + } + + if (!rdata || data_len < 68) { + return False; + } + + if (c_time) { + *c_time = interpret_long_date(rdata+0) - cli->serverzone; + } + if (a_time) { + *a_time = interpret_long_date(rdata+8) - cli->serverzone; + } + if (m_time) { + *m_time = interpret_long_date(rdata+16) - cli->serverzone; + } + if (w_time) { + *w_time = interpret_long_date(rdata+24) - cli->serverzone; + } + if (mode) { + *mode = SVAL(rdata, 32); + } + if (size) { + *size = IVAL2_TO_SMB_BIG_UINT(rdata,48); + } + if (ino) { + *ino = IVAL(rdata, 64); + } + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + return True; +} + + +/**************************************************************************** +send a qpathinfo BASIC_INFO call +****************************************************************************/ +BOOL cli_qpathinfo_basic( struct cli_state *cli, const char *name, + SMB_STRUCT_STAT *sbuf, uint32 *attributes ) +{ + unsigned int param_len = 0; + unsigned int data_len = 0; + uint16 setup = TRANSACT2_QPATHINFO; + char param[sizeof(pstring)+6]; + char *rparam=NULL, *rdata=NULL; + char *p; + pstring path; + int len; + + /* send full paths to dfs root shares */ + + if ( cli->dfsroot ) + pstr_sprintf(path, "\\%s\\%s\\%s", cli->desthost, cli->share, name ); + else + pstrcpy( path, name ); + + /* cleanup */ + + len = strlen( path ); + if ( path[len] == '\\' ) + path[len] = '\0'; + + p = param; + memset(p, 0, 6); + SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO); + p += 6; + p += clistr_push(cli, p, path, sizeof(pstring)-6, STR_TERMINATE); + param_len = PTR_DIFF(p, param); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, /* name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 2, /* param, length, max */ + NULL, 0, cli->max_xmit /* data, length, max */ + )) { + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return False; + } + + if (data_len < 36) { + SAFE_FREE(rdata); + SAFE_FREE(rparam); + return False; + } + + sbuf->st_atime = interpret_long_date( rdata+8 ); + sbuf->st_mtime = interpret_long_date( rdata+16 ); + sbuf->st_ctime = interpret_long_date( rdata+24 ); + + *attributes = IVAL( rdata, 32 ); + + SAFE_FREE(rparam); + SAFE_FREE(rdata); + + return True; +} + +/**************************************************************************** +send a qfileinfo call +****************************************************************************/ + +BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen) +{ + unsigned int data_len = 0; + unsigned int param_len = 0; + uint16 setup = TRANSACT2_QFILEINFO; + pstring param; + char *rparam=NULL, *rdata=NULL; + + *poutdata = NULL; + *poutlen = 0; + + /* if its a win95 server then fail this - win95 totally screws it + up */ + if (cli->win95) + return False; + + param_len = 4; + + memset(param, 0, param_len); + SSVAL(param, 0, fnum); + SSVAL(param, 2, level); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, /* name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 2, /* param, length, max */ + NULL, data_len, cli->max_xmit /* data, length, max */ + )) { + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return False; + } + + *poutdata = memdup(rdata, data_len); + *poutlen = data_len; + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + return True; +} + + + +/**************************************************************************** +send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call +****************************************************************************/ +NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name) +{ + unsigned int data_len = 0; + unsigned int param_len = 0; + uint16 setup = TRANSACT2_QPATHINFO; + pstring param; + char *rparam=NULL, *rdata=NULL; + int count=8; + char *p; + BOOL ret; + unsigned int len; + + p = param; + memset(p, 0, 6); + SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO); + p += 6; + p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE); + + param_len = PTR_DIFF(p, param); + + do { + ret = (cli_send_trans(cli, SMBtrans2, + NULL, /* Name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 10, /* param, length, max */ + NULL, data_len, cli->max_xmit /* data, length, max */ + ) && + cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)); + if (!ret && cli_is_dos_error(cli)) { + /* we need to work around a Win95 bug - sometimes + it gives ERRSRV/ERRerror temprarily */ + uint8 eclass; + uint32 ecode; + cli_dos_error(cli, &eclass, &ecode); + if (eclass != ERRSRV || ecode != ERRerror) break; + smb_msleep(100); + } + } while (count-- && ret==False); + + if (!ret || !rdata || data_len < 4) { + return NT_STATUS_UNSUCCESSFUL; + } + + len = IVAL(rdata, 0); + + if (len > data_len - 4) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE); + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + + return NT_STATUS_OK; +}