summaryrefslogtreecommitdiffstats
path: root/source3/rpc_server
diff options
context:
space:
mode:
Diffstat (limited to 'source3/rpc_server')
-rw-r--r--source3/rpc_server/srv_eventlog.c6
-rw-r--r--source3/rpc_server/srv_eventlog_nt.c1585
-rw-r--r--source3/rpc_server/srv_lsa_hnd.c6
-rw-r--r--source3/rpc_server/srv_lsa_nt.c7
-rw-r--r--source3/rpc_server/srv_netlog_nt.c269
-rw-r--r--source3/rpc_server/srv_ntsvcs.c220
-rw-r--r--source3/rpc_server/srv_ntsvcs_nt.c174
-rw-r--r--source3/rpc_server/srv_pipe.c1863
-rw-r--r--source3/rpc_server/srv_pipe_hnd.c217
-rw-r--r--source3/rpc_server/srv_reg.c57
-rw-r--r--source3/rpc_server/srv_reg_nt.c436
-rw-r--r--source3/rpc_server/srv_samr_nt.c153
-rw-r--r--source3/rpc_server/srv_samr_util.c4
-rw-r--r--source3/rpc_server/srv_spoolss_nt.c55
-rw-r--r--source3/rpc_server/srv_srvsvc_nt.c5
-rw-r--r--source3/rpc_server/srv_svcctl.c76
-rw-r--r--source3/rpc_server/srv_svcctl_nt.c694
17 files changed, 3403 insertions, 2424 deletions
diff --git a/source3/rpc_server/srv_eventlog.c b/source3/rpc_server/srv_eventlog.c
index 65b10e8fe40..ae15d43f4ba 100644
--- a/source3/rpc_server/srv_eventlog.c
+++ b/source3/rpc_server/srv_eventlog.c
@@ -27,7 +27,6 @@ static BOOL api_eventlog_open_eventlog(pipes_struct *p)
{
EVENTLOG_Q_OPEN_EVENTLOG q_u;
EVENTLOG_R_OPEN_EVENTLOG r_u;
-
prs_struct *data = &p->in_data.data;
prs_struct *rdata = &p->out_data.rdata;
@@ -53,7 +52,6 @@ static BOOL api_eventlog_close_eventlog(pipes_struct *p)
{
EVENTLOG_Q_CLOSE_EVENTLOG q_u;
EVENTLOG_R_CLOSE_EVENTLOG r_u;
-
prs_struct *data = &p->in_data.data;
prs_struct *rdata = &p->out_data.rdata;
@@ -79,7 +77,6 @@ static BOOL api_eventlog_get_num_records(pipes_struct *p)
{
EVENTLOG_Q_GET_NUM_RECORDS q_u;
EVENTLOG_R_GET_NUM_RECORDS r_u;
-
prs_struct *data = &p->in_data.data;
prs_struct *rdata = &p->out_data.rdata;
@@ -105,7 +102,6 @@ static BOOL api_eventlog_get_oldest_entry(pipes_struct *p)
{
EVENTLOG_Q_GET_OLDEST_ENTRY q_u;
EVENTLOG_R_GET_OLDEST_ENTRY r_u;
-
prs_struct *data = &p->in_data.data;
prs_struct *rdata = &p->out_data.rdata;
@@ -131,7 +127,6 @@ static BOOL api_eventlog_read_eventlog(pipes_struct *p)
{
EVENTLOG_Q_READ_EVENTLOG q_u;
EVENTLOG_R_READ_EVENTLOG r_u;
-
prs_struct *data = &p->in_data.data;
prs_struct *rdata = &p->out_data.rdata;
@@ -157,7 +152,6 @@ static BOOL api_eventlog_clear_eventlog(pipes_struct *p)
{
EVENTLOG_Q_CLEAR_EVENTLOG q_u;
EVENTLOG_R_CLEAR_EVENTLOG r_u;
-
prs_struct *data = &p->in_data.data;
prs_struct *rdata = &p->out_data.rdata;
diff --git a/source3/rpc_server/srv_eventlog_nt.c b/source3/rpc_server/srv_eventlog_nt.c
index a9b0c9bed80..414c99d28e2 100644
--- a/source3/rpc_server/srv_eventlog_nt.c
+++ b/source3/rpc_server/srv_eventlog_nt.c
@@ -1,7 +1,8 @@
/*
* Unix SMB/CIFS implementation.
* RPC Pipe client / server routines
- * Copyright (C) Marcin Krzysztof Porwit 2005.
+ * Copyright (C) Marcin Krzysztof Porwit 2005,
+ * Copyright (C) Gerald (Jerry) Carter 2005.
*
* 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
@@ -23,56 +24,152 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_SRV
-typedef struct eventlog_info
+typedef struct {
+ char *logname;
+ char *servername;
+ uint32 num_records;
+ uint32 oldest_entry;
+ uint32 flags;
+} EventlogInfo;
+
+
+/********************************************************************
+ Inform the external eventlog machinery of default values (on startup
+ probably)
+********************************************************************/
+
+void eventlog_refresh_external_parameters( NT_USER_TOKEN *token )
{
- /* for use by the \PIPE\eventlog policy */
- fstring source_log_file_name;
- fstring source_server_name;
- fstring handle_string;
- uint32 num_records;
- uint32 oldest_entry;
- uint32 active_entry;
- uint32 flags;
-} Eventlog_info;
+ const char **elogs = lp_eventlog_list();
+ int i;
+
+ if ( !elogs )
+ return ;
+
+ if ( !*lp_eventlog_control_cmd() )
+ return;
+
+ for ( i=0; elogs[i]; i++ ) {
+
+ DEBUG(10,("eventlog_refresh_external_parameters: Refreshing =>[%s]\n",
+ elogs[i]));
+
+ if ( !control_eventlog_hook( token, elogs[i] ) ) {
+ DEBUG(0,("eventlog_refresh_external_parameters: failed to refresh [%s]\n",
+ elogs[i]));
+ }
+ }
+
+ return;
+}
+
+/********************************************************************
+********************************************************************/
static void free_eventlog_info(void *ptr)
{
- struct eventlog_info *info = (struct eventlog_info *)ptr;
- memset(info->source_log_file_name, '0', sizeof(*(info->source_log_file_name)));
- memset(info->source_server_name, '0', sizeof(*(info->source_server_name)));
- memset(info->handle_string, '0', sizeof(*(info->handle_string)));
- memset(info, 0, sizeof(*(info)));
- SAFE_FREE(info);
+ TALLOC_FREE( ptr );
}
-static Eventlog_info *find_eventlog_info_by_hnd(pipes_struct *p,
- POLICY_HND *handle)
+/********************************************************************
+********************************************************************/
+
+static EventlogInfo *find_eventlog_info_by_hnd(pipes_struct *p, POLICY_HND *handle)
{
- Eventlog_info *info = NULL;
+ EventlogInfo *info;
- if(!(find_policy_by_hnd(p,handle,(void **)&info)))
- {
- DEBUG(2,("find_eventlog_info_by_hnd: eventlog not found.\n"));
- }
+ if ( !find_policy_by_hnd(p,handle,(void **)&info) ) {
+ DEBUG(2,("find_eventlog_info_by_hnd: eventlog not found.\n"));
+ return NULL;
+ }
- return info;
+ return info;
}
-void policy_handle_to_string(POLICY_HND *handle, fstring *dest)
+/********************************************************************
+ Callout to control the specified event log - passing out only
+ the MaxSize and Retention values, along with eventlog name
+ uses smbrun...
+ INPUT: <control_cmd> <log name> <retention> <maxsize>
+ OUTPUT: nothing
+********************************************************************/
+
+BOOL control_eventlog_hook(NT_USER_TOKEN *token, const char *elogname )
{
- memset(dest, 0, sizeof(*dest));
- snprintf((char *)dest, sizeof(*dest), "%08X-%08X-%04X-%04X-%02X%02X%02X%02X%02X",
- handle->data1,
- handle->data2,
- handle->data3,
- handle->data4,
- handle->data5[0],
- handle->data5[1],
- handle->data5[2],
- handle->data5[3],
- handle->data5[4]);
+ char *cmd = lp_eventlog_control_cmd();
+ pstring command;
+ int ret;
+ int fd = -1;
+ uint32 uiMaxSize, uiRetention;
+ pstring path;
+ REGISTRY_KEY *keyinfo;
+ REGISTRY_VALUE *val;
+ REGVAL_CTR *values;
+ WERROR wresult;
+
+ if ( !cmd || !*cmd ) {
+ DEBUG(0, ("control_eventlog_hook: No \"eventlog control command\" defined in smb.conf!\n"));
+ return False;
+ }
+
+ /* set resonable defaults. 512Kb on size and 1 week on time */
+
+ uiMaxSize = 0x80000;
+ uiRetention = 604800;
+
+ /* the general idea is to internally open the registry
+ key and retreive the values. That way we can continue
+ to use the same fetch/store api that we use in
+ srv_reg_nt.c */
+
+ pstr_sprintf( path, "%s/%s", KEY_EVENTLOG, elogname );
+ wresult = regkey_open_internal( &keyinfo, path, token, REG_KEY_READ );
+
+ if ( !W_ERROR_IS_OK( wresult ) ) {
+ DEBUG(4,("control_eventlog_hook: Failed to open key [%s] (%s)\n",
+ path, dos_errstr(wresult) ));
+ return False;
+ }
+
+ if ( !(values = TALLOC_ZERO_P( keyinfo, REGVAL_CTR )) ) {
+ TALLOC_FREE( keyinfo );
+ DEBUG(0,("control_eventlog_hook: talloc() failed!\n"));
+
+ return False;
+ }
+ fetch_reg_values( keyinfo, values );
+
+ if ( (val = regval_ctr_getvalue( values, "Retention" )) != NULL )
+ uiRetention = IVAL( regval_data_p(val), 0 );
+
+ if ( (val = regval_ctr_getvalue( values, "MaxSize" )) != NULL )
+ uiMaxSize = IVAL( regval_data_p(val), 0 );
+
+ TALLOC_FREE( keyinfo );
+
+ /* now run the command */
+
+ pstr_sprintf(command, "%s \"%s\" %u %u", cmd, elogname, uiRetention, uiMaxSize );
+
+ DEBUG(10, ("control_eventlog_hook: Running [%s]\n", command));
+ ret = smbrun(command, &fd);
+ DEBUGADD(10, ("returned [%d]\n", ret));
+
+ if ( ret != 0 ) {
+ DEBUG(10,("control_eventlog_hook: Command returned [%d]\n", ret));
+ if (fd != -1 )
+ close(fd);
+ return False;
+ }
+
+ close(fd);
+ return True;
}
+
+/********************************************************************
+********************************************************************/
+
/**
* Callout to open the specified event log
*
@@ -81,109 +178,53 @@ void policy_handle_to_string(POLICY_HND *handle, fstring *dest)
* OUTPUT: the string "SUCCESS" if the command succeeded
* no such string if there was a failure.
*/
-static BOOL _eventlog_open_eventlog_hook(Eventlog_info *info)
+static BOOL open_eventlog_hook( EventlogInfo *info )
{
- char *cmd = lp_eventlog_open_cmd();
- char **qlines;
- pstring command;
- int numlines = 0;
- int ret;
- int fd = -1;
-
- if(cmd == NULL || strlen(cmd) == 0)
- {
- DEBUG(0, ("Must define an \"eventlog open command\" entry in the config.\n"));
- return False;
- }
-
- memset(command, 0, sizeof(command));
- slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\"",
- cmd,
- info->source_log_file_name,
- info->handle_string);
-
- DEBUG(10, ("Running [%s]\n", command));
- ret = smbrun(command, &fd);
- DEBUGADD(10, ("returned [%d]\n", ret));
-
- if(ret != 0)
- {
- if(fd != -1)
- close(fd);
- return False;
- }
+ char *cmd = lp_eventlog_open_cmd();
+ char **qlines;
+ pstring command;
+ int numlines = 0;
+ int ret;
+ int fd = -1;
+
+ if ( !cmd || !*cmd ) {
+ DEBUG(0, ("Must define an \"eventlog open command\" entry in the config.\n"));
+ return False;
+ }
+
+ pstr_sprintf(command, "%s \"%s\"", cmd, info->logname );
- qlines = fd_lines_load(fd, &numlines);
- DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
- close(fd);
+ DEBUG(10, ("Running [%s]\n", command));
+ ret = smbrun(command, &fd);
+ DEBUGADD(10, ("returned [%d]\n", ret));
- if(numlines)
- {
- DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
- if(0 == strncmp(qlines[0], "SUCCESS", strlen("SUCCESS")))
- {
- DEBUGADD(10, ("Able to open [%s].\n", info->source_log_file_name));
- file_lines_free(qlines);
- return True;
+ if(ret != 0) {
+ if(fd != -1) {
+ close(fd);
+ }
+ return False;
}
- }
- file_lines_free(qlines);
- return False;
-}
+ qlines = fd_lines_load(fd, &numlines);
+ DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
+ close(fd);
-WERROR _eventlog_open_eventlog(pipes_struct *p,
- EVENTLOG_Q_OPEN_EVENTLOG *q_u,
- EVENTLOG_R_OPEN_EVENTLOG *r_u)
-{
- Eventlog_info *info = NULL;
-
- if(!q_u || !r_u)
- return WERR_NOMEM;
-
- if((info = SMB_MALLOC_P(Eventlog_info)) == NULL)
- return WERR_NOMEM;
-
- ZERO_STRUCTP(info);
-
- if(q_u->servername_ptr != 0)
- {
- unistr2_to_ascii(info->source_server_name, &(q_u->servername), sizeof(info->source_server_name));
- }
- else
- {
- /* if servername == NULL, use the local computer */
- fstrcpy(info->source_server_name, global_myname());
- }
- DEBUG(10, ("_eventlog_open_eventlog: Using [%s] as the server name.\n", info->source_server_name));
-
- if(q_u->sourcename_ptr != 0)
- {
- unistr2_to_ascii(info->source_log_file_name, &(q_u->sourcename), sizeof(info->source_log_file_name));
- }
- else
- {
- /* if sourcename == NULL, default to "Application" log */
- fstrcpy(info->source_log_file_name, "Application");
- }
- DEBUG(10, ("_eventlog_open_eventlog: Using [%s] as the source log file.\n", info->source_log_file_name));
-
- if(!create_policy_hnd(p, &(r_u->handle), free_eventlog_info, (void *)info))
- {
- free_eventlog_info(info);
- return WERR_NOMEM;
- }
-
- policy_handle_to_string(&r_u->handle, &info->handle_string);
-
- if(!(_eventlog_open_eventlog_hook(info)))
- {
- close_policy_hnd(p, &r_u->handle);
- return WERR_BADFILE;
- }
-
- return WERR_OK;
+ if(numlines) {
+ DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
+ if(0 == strncmp(qlines[0], "SUCCESS", strlen("SUCCESS"))) {
+ DEBUGADD(10, ("Able to open [%s].\n", info->logname));
+ file_lines_free(qlines);
+ return True;
+ }
+ }
+
+ file_lines_free(qlines);
+
+ return False;
}
+
+/********************************************************************
+********************************************************************/
/**
* Callout to get the number of records in the specified event log
*
@@ -192,74 +233,52 @@ WERROR _eventlog_open_eventlog(pipes_struct *p,
* OUTPUT: A single line with a single integer containing the number of
* entries in the log. If there are no entries in the log, return 0.
*/
-static BOOL _eventlog_get_num_records_hook(Eventlog_info *info)
-{
- char *cmd = lp_eventlog_num_records_cmd();
- char **qlines;
- pstring command;
- int numlines = 0;
- int ret;
- int fd = -1;
-
- if(cmd == NULL || strlen(cmd) == 0)
- {
- DEBUG(0, ("Must define an \"eventlog num records command\" entry in the config.\n"));
- return False;
- }
-
- memset(command, 0, sizeof(command));
- slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\"",
- cmd,
- info->source_log_file_name,
- info->handle_string);
-
- DEBUG(10, ("Running [%s]\n", command));
- ret = smbrun(command, &fd);
- DEBUGADD(10, ("returned [%d]\n", ret));
-
- if(ret != 0)
- {
- if(fd != -1)
- close(fd);
- return False;
- }
- qlines = fd_lines_load(fd, &numlines);
- DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
- close(fd);
+static BOOL get_num_records_hook(EventlogInfo *info)
+{
+ char *cmd = lp_eventlog_num_records_cmd();
+ char **qlines;
+ pstring command;
+ int numlines = 0;
+ int ret;
+ int fd = -1;
+
+ if ( !cmd || !*cmd ) {
+ DEBUG(0, ("Must define an \"eventlog num records command\" entry in the config.\n"));
+ return False;
+ }
- if(numlines)
- {
- DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
- sscanf(qlines[0], "%d", &(info->num_records));
- file_lines_free(qlines);
- return True;
- }
+ pstr_sprintf( command, "%s \"%s\"", cmd, info->logname );
- file_lines_free(qlines);
- return False;
-}
+ DEBUG(10, ("Running [%s]\n", command));
+ ret = smbrun(command, &fd);
+ DEBUGADD(10, ("returned [%d]\n", ret));
-WERROR _eventlog_get_num_records(pipes_struct *p,
- EVENTLOG_Q_GET_NUM_RECORDS *q_u,
- EVENTLOG_R_GET_NUM_RECORDS *r_u)
-{
- Eventlog_info *info = NULL;
- POLICY_HND *handle = NULL;
+ if(ret != 0) {
+ if(fd != -1) {
+ close(fd);
+ }
+ return False;
+ }
- if(!q_u || !r_u)
- return WERR_NOMEM;
+ qlines = fd_lines_load(fd, &numlines);
+ DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
+ close(fd);
- handle = &(q_u->handle);
- info = find_eventlog_info_by_hnd(p, handle);
+ if(numlines) {
+ DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
+ sscanf(qlines[0], "%d", &(info->num_records));
+ file_lines_free(qlines);
+ return True;
+ }
- if(!(_eventlog_get_num_records_hook(info)))
- return WERR_BADFILE;
+ file_lines_free(qlines);
+ return False;
+}
- r_u->num_records = info->num_records;
+/********************************************************************
+********************************************************************/
- return WERR_OK;
-}
/**
* Callout to find the oldest record in the log
*
@@ -269,75 +288,51 @@ WERROR _eventlog_get_num_records(pipes_struct *p,
* oldest entry. Must be 1 or greater.
* If there are no entries in the log, returns a 0
*/
-static BOOL _eventlog_get_oldest_entry_hook(Eventlog_info *info)
-{
- char *cmd = lp_eventlog_oldest_record_cmd();
- char **qlines;
- pstring command;
- int numlines = 0;
- int ret;
- int fd = -1;
-
- if(cmd == NULL || strlen(cmd) == 0)
- {
- DEBUG(0, ("Must define an \"eventlog oldest record command\" entry in the config.\n"));
- return False;
- }
-
- memset(command, 0, sizeof(command));
- slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\"",
- cmd,
- info->source_log_file_name,
- info->handle_string);
-
- DEBUG(10, ("Running [%s]\n", command));
- ret = smbrun(command, &fd);
- DEBUGADD(10, ("returned [%d]\n", ret));
-
- if(ret != 0)
- {
- if(fd != -1)
- close(fd);
- return False;
- }
- qlines = fd_lines_load(fd, &numlines);
- DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
- close(fd);
-
- if(numlines)
- {
- DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
- sscanf(qlines[0], "%d", &(info->oldest_entry));
- file_lines_free(qlines);
- return True;
- }
-
- file_lines_free(qlines);
- return False;
-}
-
-WERROR _eventlog_get_oldest_entry(pipes_struct *p,
- EVENTLOG_Q_GET_OLDEST_ENTRY *q_u,
- EVENTLOG_R_GET_OLDEST_ENTRY *r_u)
+static BOOL get_oldest_entry_hook(EventlogInfo *info)
{
- Eventlog_info *info = NULL;
- POLICY_HND *handle = NULL;
+ char *cmd = lp_eventlog_oldest_record_cmd();
+ char **qlines;
+ pstring command;
+ int numlines = 0;
+ int ret;
+ int fd = -1;
+
+ if ( !cmd || !*cmd ) {
+ DEBUG(0, ("Must define an \"eventlog oldest record command\" entry in the config.\n"));
+ return False;
+ }
+
+ pstr_sprintf( command, "%s \"%s\"", cmd, info->logname );
- if(!q_u || !r_u)
- return WERR_NOMEM;
+ DEBUG(10, ("Running [%s]\n", command));
+ ret = smbrun(command, &fd);
+ DEBUGADD(10, ("returned [%d]\n", ret));
- handle = &(q_u->handle);
- info = find_eventlog_info_by_hnd(p, handle);
+ if(ret != 0) {
+ if(fd != -1) {
+ close(fd);
+ }
+ return False;
+ }
- if(!(_eventlog_get_oldest_entry_hook(info)))
- return WERR_BADFILE;
+ qlines = fd_lines_load(fd, &numlines);
+ DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
+ close(fd);
- r_u->oldest_entry = info->oldest_entry;
+ if(numlines) {
+ DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
+ sscanf(qlines[0], "%d", &(info->oldest_entry));
+ file_lines_free(qlines);
+ return True;
+ }
- return WERR_OK;
+ file_lines_free(qlines);
+ return False;
}
+/********************************************************************
+********************************************************************/
/**
* Callout to close the specified event log
*
@@ -346,270 +341,206 @@ WERROR _eventlog_get_oldest_entry(pipes_struct *p,
* OUTPUT: the string "SUCCESS" if the command succeeded
* no such string if there was a failure.
*/
-static BOOL _eventlog_close_eventlog_hook(Eventlog_info *info)
+
+static BOOL close_eventlog_hook(EventlogInfo *info)
{
- char *cmd = lp_eventlog_close_cmd();
- char **qlines;
- pstring command;
- int numlines = 0;
- int ret;
- int fd = -1;
-
- if(cmd == NULL || strlen(cmd) == 0)
- {
- DEBUG(0, ("Must define an \"eventlog close command\" entry in the config.\n"));
- return False;
- }
-
- memset(command, 0, sizeof(command));
- slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\"",
- cmd,
- info->source_log_file_name,
- info->handle_string);
-
- DEBUG(10, ("Running [%s]\n", command));
- ret = smbrun(command, &fd);
- DEBUGADD(10, ("returned [%d]\n", ret));
-
- if(ret != 0)
- {
- if(fd != -1)
- close(fd);
- return False;
- }
+ char *cmd = lp_eventlog_close_cmd();
+ char **qlines;
+ pstring command;
+ int numlines = 0;
+ int ret;
+ int fd = -1;
+
+ if ( !cmd || !*cmd ) {
+ DEBUG(0, ("Must define an \"eventlog close command\" entry in the config.\n"));
+ return False;
+ }
- qlines = fd_lines_load(fd, &numlines);
- DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
- close(fd);
+ pstr_sprintf( command, "%s \"%s\"", cmd, info->logname );
- if(numlines)
- {
- DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
- if(0 == strncmp(qlines[0], "SUCCESS", strlen("SUCCESS")))
- {
- DEBUGADD(10, ("Able to close [%s].\n", info->source_log_file_name));
- file_lines_free(qlines);
- return True;
- }
- }
+ DEBUG(10, ("Running [%s]\n", command));
+ ret = smbrun(command, &fd);
+ DEBUGADD(10, ("returned [%d]\n", ret));
- file_lines_free(qlines);
- return False;
-}
+ if(ret != 0) {
+ if(fd != -1) {
+ close(fd);
+ }
+ return False;
+ }
-WERROR _eventlog_close_eventlog(pipes_struct *p,
- EVENTLOG_Q_CLOSE_EVENTLOG *q_u,
- EVENTLOG_R_CLOSE_EVENTLOG *r_u)
-{
- Eventlog_info *info = NULL;
- POLICY_HND *handle;
+ qlines = fd_lines_load(fd, &numlines);
+ DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
+ close(fd);
- if(!q_u || !r_u)
- return WERR_NOMEM;
+ if(numlines) {
+ DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
+ if(0 == strncmp(qlines[0], "SUCCESS", 7)) {
+ DEBUGADD(10, ("Able to close [%s].\n", info->logname));
+ file_lines_free(qlines);
+ return True;
+ }
+ }
- handle = &(q_u->handle);
-
- info = find_eventlog_info_by_hnd(p, handle);
- if(!(_eventlog_close_eventlog_hook(info)))
- return WERR_BADFILE;
-
- if(!(close_policy_hnd(p, handle)))
- {
- /* WERR_NOMEM is probably not the correct error, but until I figure out a better
- one it will have to do */
- return WERR_NOMEM;
- }
-
- return WERR_OK;
+ file_lines_free(qlines);
+ return False;
}
-static BOOL _eventlog_read_parse_line(char *line, Eventlog_entry *entry, BOOL *eor)
+/********************************************************************
+********************************************************************/
+
+static BOOL parse_logentry(char *line, Eventlog_entry *entry, BOOL *eor)
{
- char *start = NULL, *stop = NULL;
- pstring temp;
- int temp_len = 0, i;
+ char *start = NULL, *stop = NULL;
+ pstring temp;
+ int temp_len = 0, i;
- start = line;
+ start = line;
- /* empty line signyfiying record delimeter, or we're at the end of the buffer */
- if(start == NULL || strlen(start) == 0)
- {
- DEBUG(6, ("_eventlog_read_parse_line: found end-of-record indicator.\n"));
- *eor = True;
- return True;
- }
- if(!(stop = strchr(line, ':')))
- return False;
+ /* empty line signyfiying record delimeter, or we're at the end of the buffer */
+ if(start == NULL || strlen(start) == 0) {
+ DEBUG(6, ("parse_logentry: found end-of-record indicator.\n"));
+ *eor = True;
+ return True;
+ }
+ if(!(stop = strchr(line, ':'))) {
+ return False;
+ }
- DEBUG(6, ("_eventlog_read_parse_line: trying to parse [%s].\n", line));
-
- if(0 == strncmp(start, "LEN", stop - start))
- {
- /* This will get recomputed later anyway -- probably not necessary */
- entry->record.length = atoi(stop + 1);
- }
- else if(0 == strncmp(start, "RS1", stop - start))
- {
- /* For now all these reserved entries seem to have the same value,
- which can be hardcoded to int(1699505740) for now */
- entry->record.reserved1 = atoi(stop + 1);
- }
- else if(0 == strncmp(start, "RCN", stop - start))
- {
- entry->record.record_number = atoi(stop + 1);
- }
- else if(0 == strncmp(start, "TMG", stop - start))
- {
- entry->record.time_generated = atoi(stop + 1);
- }
- else if(0 == strncmp(start, "TMW", stop - start))
- {
- entry->record.time_written = atoi(stop + 1);
- }
- else if(0 == strncmp(start, "EID", stop - start))
- {
- entry->record.event_id = atoi(stop + 1);
- }
- else if(0 == strncmp(start, "ETP", stop - start))
- {
- if(strstr(start, "ERROR"))
- {
- entry->record.event_type = EVENTLOG_ERROR_TYPE;
- }
- else if(strstr(start, "WARNING"))
- {
- entry->record.event_type = EVENTLOG_WARNING_TYPE;
- }
- else if(strstr(start, "INFO"))
- {
- entry->record.event_type = EVENTLOG_INFORMATION_TYPE;
- }
- else if(strstr(start, "AUDIT_SUCCESS"))
- {
- entry->record.event_type = EVENTLOG_AUDIT_SUCCESS;
- }
- else if(strstr(start, "AUDIT_FAILURE"))
- {
- entry->record.event_type = EVENTLOG_AUDIT_FAILURE;
- }
- else if(strstr(start, "SUCCESS"))
- {
- entry->record.event_type = EVENTLOG_SUCCESS;
- }
- else
- {
- /* some other eventlog type -- currently not defined in MSDN docs, so error out */
- return False;
- }
- }
+ DEBUG(6, ("parse_logentry: trying to parse [%s].\n", line));
+
+ if(0 == strncmp(start, "LEN", stop - start)) {
+ /* This will get recomputed later anyway -- probably not necessary */
+ entry->record.length = atoi(stop + 1);
+ } else if(0 == strncmp(start, "RS1", stop - start)) {
+ /* For now all these reserved entries seem to have the same value,
+ which can be hardcoded to int(1699505740) for now */
+ entry->record.reserved1 = atoi(stop + 1);
+ } else if(0 == strncmp(start, "RCN", stop - start)) {
+ entry->record.record_number = atoi(stop + 1);
+ } else if(0 == strncmp(start, "TMG", stop - start)) {
+ entry->record.time_generated = atoi(stop + 1);
+ } else if(0 == strncmp(start, "TMW", stop - start)) {
+ entry->record.time_written = atoi(stop + 1);
+ } else if(0 == strncmp(start, "EID", stop - start)) {
+ entry->record.event_id = atoi(stop + 1);
+ } else if(0 == strncmp(start, "ETP", stop - start)) {
+ if(strstr(start, "ERROR")) {
+ entry->record.event_type = EVENTLOG_ERROR_TYPE;
+ } else if(strstr(start, "WARNING")) {
+ entry->record.event_type = EVENTLOG_WARNING_TYPE;
+ } else if(strstr(start, "INFO")) {
+ entry->record.event_type = EVENTLOG_INFORMATION_TYPE;
+ } else if(strstr(start, "AUDIT_SUCCESS")) {
+ entry->record.event_type = EVENTLOG_AUDIT_SUCCESS;
+ } else if(strstr(start, "AUDIT_FAILURE")) {
+ entry->record.event_type = EVENTLOG_AUDIT_FAILURE;
+ } else if(strstr(start, "SUCCESS")) {
+ entry->record.event_type = EVENTLOG_SUCCESS;
+ } else {
+ /* some other eventlog type -- currently not defined in MSDN docs, so error out */
+ return False;
+ }
+ }
/*
- else if(0 == strncmp(start, "NST", stop - start))
- {
- entry->record.num_strings = atoi(stop + 1);
- }
+ else if(0 == strncmp(start, "NST", stop - start))
+ {
+ entry->record.num_strings = atoi(stop + 1);
+ }
*/
- else if(0 == strncmp(start, "ECT", stop - start))
- {
- entry->record.event_category = atoi(stop + 1);
- }
- else if(0 == strncmp(start, "RS2", stop - start))
- {
- entry->record.reserved2 = atoi(stop + 1);
- }
- else if(0 == strncmp(start, "CRN", stop - start))
- {
- entry->record.closing_record_number = atoi(stop + 1);
- }
- else if(0 == strncmp(start, "USL", stop - start))
- {
- entry->record.user_sid_length = atoi(stop + 1);
- }
- else if(0 == strncmp(start, "SRC", stop - start))
- {
- memset(temp, 0, sizeof(temp));
- stop++;
- while(isspace(stop[0]))
- stop++;
- temp_len = strlen(stop);
- strncpy(temp, stop, temp_len);
- rpcstr_push((void *)(entry->data_record.source_name), temp,
- sizeof(entry->data_record.source_name), STR_TERMINATE);
- entry->data_record.source_name_len = (strlen_w(entry->data_record.source_name)* 2) + 2;
- }
- else if(0 == strncmp(start, "SRN", stop - start))
- {
- memset(temp, 0, sizeof(temp));
- stop++;
- while(isspace(stop[0]))
- stop++;
- temp_len = strlen(stop);
- strncpy(temp, stop, temp_len);
- rpcstr_push((void *)(entry->data_record.computer_name), temp,
- sizeof(entry->data_record.computer_name), STR_TERMINATE);
- entry->data_record.computer_name_len = (strlen_w(entry->data_record.computer_name)* 2) + 2;
- }
- else if(0 == strncmp(start, "SID", stop - start))
- {
- memset(temp, 0, sizeof(temp));
- stop++;
- while(isspace(stop[0]))
- stop++;
- temp_len = strlen(stop);
- strncpy(temp, stop, temp_len);
- rpcstr_push((void *)(entry->data_record.sid), temp,
- sizeof(entry->data_record.sid), STR_TERMINATE);
- entry->record.user_sid_length = (strlen_w(entry->data_record.sid) * 2) + 2;
- }
- else if(0 == strncmp(start, "STR", stop - start))
- {
- /* skip past initial ":" */
- stop++;
- /* now skip any other leading whitespace */
- while(isspace(stop[0]))
- stop++;
- temp_len = strlen(stop);
- memset(temp, 0, sizeof(temp));
- strncpy(temp, stop, temp_len);
- rpcstr_push((void *)(entry->data_record.strings + entry->data_record.strings_len),
- temp,
- sizeof(entry->data_record.strings) - entry->data_record.strings_len,
- STR_TERMINATE);
- entry->data_record.strings_len += temp_len + 1;
- fprintf(stderr, "Dumping strings:\n");
- for(i = 0; i < entry->data_record.strings_len; i++)
- {
- fputc((char)entry->data_record.strings[i], stderr);
- }
- fprintf(stderr, "\nDone\n");
- entry->record.num_strings++;
- }
- else if(0 == strncmp(start, "DAT", stop - start))
- {
- /* Now that we're done processing the STR data, adjust the length to account for
- unicode, then proceed with the DAT data. */
- entry->data_record.strings_len *= 2;
- /* skip past initial ":" */
- stop++;
- /* now skip any other leading whitespace */
- while(isspace(stop[0]))
- stop++;
- memset(temp, 0, sizeof(temp));
- temp_len = strlen(stop);
- strncpy(temp, stop, temp_len);
- rpcstr_push((void *)(entry->data_record.user_data), temp,
- sizeof(entry->data_record.user_data), STR_TERMINATE);
- entry->data_record.user_data_len = (strlen_w((const smb_ucs2_t *)entry->data_record.user_data) * 2) + 2;
- }
- else
- {
- /* some other eventlog entry -- not implemented, so dropping on the floor */
- DEBUG(10, ("Unknown entry [%s]. Ignoring.\n", line));
- /* For now return true so that we can keep on parsing this mess. Eventually
- we will return False here. */
+ else if(0 == strncmp(start, "ECT", stop - start)) {
+ entry->record.event_category = atoi(stop + 1);
+ } else if(0 == strncmp(start, "RS2", stop - start)) {
+ entry->record.reserved2 = atoi(stop + 1);
+ } else if(0 == strncmp(start, "CRN", stop - start)) {
+ entry->record.closing_record_number = atoi(stop + 1);
+ } else if(0 == strncmp(start, "USL", stop - start)) {
+ entry->record.user_sid_length = atoi(stop + 1);
+ } else if(0 == strncmp(start, "SRC", stop - start)) {
+ memset(temp, 0, sizeof(temp));
+ stop++;
+ while(isspace(stop[0])) {
+ stop++;
+ }
+ temp_len = strlen(stop);
+ strncpy(temp, stop, temp_len);
+ rpcstr_push((void *)(entry->data_record.source_name), temp,
+ sizeof(entry->data_record.source_name), STR_TERMINATE);
+ entry->data_record.source_name_len = (strlen_w(entry->data_record.source_name)* 2) + 2;
+ } else if(0 == strncmp(start, "SRN", stop - start)) {
+ memset(temp, 0, sizeof(temp));
+ stop++;
+ while(isspace(stop[0])) {
+ stop++;
+ }
+ temp_len = strlen(stop);
+ strncpy(temp, stop, temp_len);
+ rpcstr_push((void *)(entry->data_record.computer_name), temp,
+ sizeof(entry->data_record.computer_name), STR_TERMINATE);
+ entry->data_record.computer_name_len = (strlen_w(entry->data_record.computer_name)* 2) + 2;
+ } else if(0 == strncmp(start, "SID", stop - start)) {
+ memset(temp, 0, sizeof(temp));
+ stop++;
+ while(isspace(stop[0])) {
+ stop++;
+ }
+ temp_len = strlen(stop);
+ strncpy(temp, stop, temp_len);
+ rpcstr_push((void *)(entry->data_record.sid), temp,
+ sizeof(entry->data_record.sid), STR_TERMINATE);
+ entry->record.user_sid_length = (strlen_w(entry->data_record.sid) * 2) + 2;
+ } else if(0 == strncmp(start, "STR", stop - start)) {
+ /* skip past initial ":" */
+ stop++;
+ /* now skip any other leading whitespace */
+ while(isspace(stop[0])) {
+ stop++;
+ }
+ temp_len = strlen(stop);
+ memset(temp, 0, sizeof(temp));
+ strncpy(temp, stop, temp_len);
+ rpcstr_push((void *)(entry->data_record.strings + entry->data_record.strings_len),
+ temp,
+ sizeof(entry->data_record.strings) - entry->data_record.strings_len,
+ STR_TERMINATE);
+ entry->data_record.strings_len += temp_len + 1;
+ fprintf(stderr, "Dumping strings:\n");
+ for(i = 0; i < entry->data_record.strings_len; i++) {
+ fputc((char)entry->data_record.strings[i], stderr);
+ }
+ fprintf(stderr, "\nDone\n");
+ entry->record.num_strings++;
+ } else if(0 == strncmp(start, "DAT", stop - start)) {
+ /* Now that we're done processing the STR data, adjust the length to account for
+ unicode, then proceed with the DAT data. */
+ entry->data_record.strings_len *= 2;
+ /* skip past initial ":" */
+ stop++;
+ /* now skip any other leading whitespace */
+ while(isspace(stop[0])) {
+ stop++;
+ }
+ entry->data_record.user_data_len = strlen(stop);
+ memset(entry->data_record.user_data, 0, sizeof(entry->data_record.user_data));
+ if(entry->data_record.user_data_len > 0) {
+ /* copy no more than the first 1024 bytes */
+ if(entry->data_record.user_data_len > sizeof(entry->data_record.user_data))
+ entry->data_record.user_data_len = sizeof(entry->data_record.user_data);
+ memcpy(entry->data_record.user_data, stop, entry->data_record.user_data_len);
+ }
+ } else {
+ /* some other eventlog entry -- not implemented, so dropping on the floor */
+ DEBUG(10, ("Unknown entry [%s]. Ignoring.\n", line));
+ /* For now return true so that we can keep on parsing this mess. Eventually
+ we will return False here. */
+ return True;
+ }
return True;
- }
- return True;
}
+
+/********************************************************************
+********************************************************************/
+
/**
* Callout to read entries from the specified event log
*
@@ -640,254 +571,162 @@ static BOOL _eventlog_read_parse_line(char *line, Eventlog_entry *entry, BOOL *e
* DAT:[(uint8)] - The user-defined data portion of the event log. Can not be multiple lines.
* <empty line> - end-of-record indicator
*/
-static BOOL _eventlog_read_eventlog_hook(Eventlog_info *info,
- Eventlog_entry *entry,
- const char *direction,
- int starting_record,
- int buffer_size,
- BOOL *eof,
- char ***buffer,
- int *numlines)
+
+static BOOL read_eventlog_hook(EventlogInfo *info, Eventlog_entry *entry,
+ const char *direction, int starting_record,
+ int buffer_size, BOOL *eof,
+ char ***buffer, int *numlines)
{
- char *cmd = lp_eventlog_read_cmd();
- pstring command;
- int ret;
- int fd = -1;
+ char *cmd = lp_eventlog_read_cmd();
+ pstring command;
+ int ret;
+ int fd = -1;
- if(info == NULL)
- return False;
+ if ( !info )
+ return False;
- if(cmd == NULL || strlen(cmd) == 0)
- {
- DEBUG(0, ("Must define an \"eventlog read command\" entry in the config.\n"));
- return False;
- }
-
- slprintf(command, sizeof(command)-1, "%s \"%s\" %s %d %d \"%s\"",
- cmd,
- info->source_log_file_name,
- direction,
- starting_record,
- buffer_size,
- info->handle_string);
-
- *numlines = 0;
-
- DEBUG(10, ("Running [%s]\n", command));
- ret = smbrun(command, &fd);
- DEBUGADD(10, ("returned [%d]\n", ret));
-
- if(ret != 0)
- {
- if(fd != -1)
- close(fd);
- return False;
- }
+ if ( !cmd || !*cmd ) {
+ DEBUG(0, ("Must define an \"eventlog read command\" entry in the config.\n"));
+ return False;
+ }
- *buffer = fd_lines_load(fd, numlines);
- DEBUGADD(10, ("Lines returned = [%d]\n", *numlines));
- close(fd);
+ pstr_sprintf( command, "%s \"%s\" %s %d %d",
+ cmd, info->logname, direction, starting_record, buffer_size );
+
+ *numlines = 0;
+
+ DEBUG(10, ("Running [%s]\n", command));
+ ret = smbrun(command, &fd);
+ DEBUGADD(10, ("returned [%d]\n", ret));
+
+ if(ret != 0) {
+ if(fd != -1) {
+ close(fd);
+ }
+ return False;
+ }
+
+ *buffer = fd_lines_load(fd, numlines);
+ DEBUGADD(10, ("Lines returned = [%d]\n", *numlines));
+ close(fd);
- if(*numlines)
- {
- /*
- for(i = 0; i < numlines; i++)
- {
- DEBUGADD(10, ("Line[%d] = %s\n", i, qlines[i]));
- _eventlog_read_parse_line(qlines[i], entry);
+ if(*numlines) {
+ /*
+ for(i = 0; i < numlines; i++)
+ {
+ DEBUGADD(10, ("Line[%d] = %s\n", i, qlines[i]));
+ parse_logentry(qlines[i], entry);
+ }
+ file_lines_free(qlines);
+ */
+ *eof = False;
+ return True;
}
- file_lines_free(qlines);
- */
- *eof = False;
- return True;
- }
- *eof = True;
+ *eof = True;
/* file_lines_free(qlines);*/
- return False;
+ return False;
}
-
-static Eventlog_entry *_eventlog_read_package_entry(prs_struct *ps,
+
+/********************************************************************
+********************************************************************/
+
+static Eventlog_entry *read_package_entry(prs_struct *ps,
EVENTLOG_Q_READ_EVENTLOG *q_u,
EVENTLOG_R_READ_EVENTLOG *r_u,
Eventlog_entry *entry)
{
- uint8 *offset;
- Eventlog_entry *ee_new = NULL;
-
- ee_new = PRS_ALLOC_MEM(ps, Eventlog_entry, 1);
- if(ee_new == NULL)
- return NULL;
-
- entry->data_record.sid_padding = ((4 - ((entry->data_record.source_name_len
- + entry->data_record.computer_name_len) % 4)) %4);
- entry->data_record.data_padding = (4 - ((entry->data_record.strings_len
- + entry->data_record.user_data_len) % 4)) % 4;
- entry->record.length = sizeof(Eventlog_record);
- entry->record.length += entry->data_record.source_name_len;
- entry->record.length += entry->data_record.computer_name_len;
- if(entry->record.user_sid_length == 0)
- {
- /* Should not pad to a DWORD boundary for writing out the sid if there is
- no SID, so just propagate the padding to pad the data */
- entry->data_record.data_padding += entry->data_record.sid_padding;
- entry->data_record.sid_padding = 0;
- }
- DEBUG(10, ("sid_padding is [%d].\n", entry->data_record.sid_padding));
- DEBUG(10, ("data_padding is [%d].\n", entry->data_record.data_padding));
-
- entry->record.length += entry->data_record.sid_padding;
- entry->record.length += entry->record.user_sid_length;
- entry->record.length += entry->data_record.strings_len;
- entry->record.length += entry->data_record.user_data_len;
- entry->record.length += entry->data_record.data_padding;
- /* need another copy of length at the end of the data */
- entry->record.length += sizeof(entry->record.length);
- DEBUG(10, ("entry->record.length is [%d].\n", entry->record.length));
- entry->data = PRS_ALLOC_MEM(ps, uint8, entry->record.length - sizeof(Eventlog_record) - sizeof(entry->record.length));
- if(entry->data == NULL)
- return NULL;
- offset = entry->data;
- memcpy(offset, &(entry->data_record.source_name), entry->data_record.source_name_len);
- offset += entry->data_record.source_name_len;
- memcpy(offset, &(entry->data_record.computer_name), entry->data_record.computer_name_len);
- offset += entry->data_record.computer_name_len;
- /* SID needs to be DWORD-aligned */
- offset += entry->data_record.sid_padding;
- entry->record.user_sid_offset = sizeof(Eventlog_record) + (offset - entry->data);
- memcpy(offset, &(entry->data_record.sid), entry->record.user_sid_length);
- offset += entry->record.user_sid_length;
- /* Now do the strings */
- entry->record.string_offset = sizeof(Eventlog_record) + (offset - entry->data);
- memcpy(offset, &(entry->data_record.strings), entry->data_record.strings_len);
- offset += entry->data_record.strings_len;
- /* Now do the data */
- entry->record.data_length = entry->data_record.user_data_len;
- entry->record.data_offset = sizeof(Eventlog_record) + (offset - entry->data);
- memcpy(offset, &(entry->data_record.user_data), entry->data_record.user_data_len);
- offset += entry->data_record.user_data_len;
-
- memcpy(&(ee_new->record), &entry->record, sizeof(Eventlog_record));
- memcpy(&(ee_new->data_record), &entry->data_record, sizeof(Eventlog_data_record));
- ee_new->data = entry->data;
-
- return ee_new;
-}
+ uint8 *offset;
+ Eventlog_entry *ee_new = NULL;
-static BOOL _eventlog_add_record_to_resp(EVENTLOG_R_READ_EVENTLOG *r_u, Eventlog_entry *ee_new)
-{
- Eventlog_entry *insert_point;
-
- insert_point=r_u->entry;
-
- if (NULL == insert_point)
- {
- r_u->entry = ee_new;
- ee_new->next = NULL;
- }
- else
- {
- while ((NULL != insert_point->next))
- {
- insert_point=insert_point->next;
- }
- ee_new->next = NULL;
- insert_point->next = ee_new;
- }
- r_u->num_records++;
- r_u->num_bytes_in_resp += ee_new->record.length;
-
- return True;
+ ee_new = PRS_ALLOC_MEM(ps, Eventlog_entry, 1);
+ if(ee_new == NULL) {
+ return NULL;
+ }
+
+ entry->data_record.sid_padding = ((4 - ((entry->data_record.source_name_len
+ + entry->data_record.computer_name_len) % 4)) %4);
+ entry->data_record.data_padding = (4 - ((entry->data_record.strings_len
+ + entry->data_record.user_data_len) % 4)) % 4;
+ entry->record.length = sizeof(Eventlog_record);
+ entry->record.length += entry->data_record.source_name_len;
+ entry->record.length += entry->data_record.computer_name_len;
+ if(entry->record.user_sid_length == 0) {
+ /* Should not pad to a DWORD boundary for writing out the sid if there is
+ no SID, so just propagate the padding to pad the data */
+ entry->data_record.data_padding += entry->data_record.sid_padding;
+ entry->data_record.sid_padding = 0;
+ }
+ DEBUG(10, ("sid_padding is [%d].\n", entry->data_record.sid_padding));
+ DEBUG(10, ("data_padding is [%d].\n", entry->data_record.data_padding));
+
+ entry->record.length += entry->data_record.sid_padding;
+ entry->record.length += entry->record.user_sid_length;
+ entry->record.length += entry->data_record.strings_len;
+ entry->record.length += entry->data_record.user_data_len;
+ entry->record.length += entry->data_record.data_padding;
+ /* need another copy of length at the end of the data */
+ entry->record.length += sizeof(entry->record.length);
+ DEBUG(10, ("entry->record.length is [%d].\n", entry->record.length));
+ entry->data = PRS_ALLOC_MEM(ps, uint8, entry->record.length - sizeof(Eventlog_record) - sizeof(entry->record.length));
+ if(entry->data == NULL) {
+ return NULL;
+ }
+ offset = entry->data;
+ memcpy(offset, &(entry->data_record.source_name), entry->data_record.source_name_len);
+ offset += entry->data_record.source_name_len;
+ memcpy(offset, &(entry->data_record.computer_name), entry->data_record.computer_name_len);
+ offset += entry->data_record.computer_name_len;
+ /* SID needs to be DWORD-aligned */
+ offset += entry->data_record.sid_padding;
+ entry->record.user_sid_offset = sizeof(Eventlog_record) + (offset - entry->data);
+ memcpy(offset, &(entry->data_record.sid), entry->record.user_sid_length);
+ offset += entry->record.user_sid_length;
+ /* Now do the strings */
+ entry->record.string_offset = sizeof(Eventlog_record) + (offset - entry->data);
+ memcpy(offset, &(entry->data_record.strings), entry->data_record.strings_len);
+ offset += entry->data_record.strings_len;
+ /* Now do the data */
+ entry->record.data_length = entry->data_record.user_data_len;
+ entry->record.data_offset = sizeof(Eventlog_record) + (offset - entry->data);
+ memcpy(offset, &(entry->data_record.user_data), entry->data_record.user_data_len);
+ offset += entry->data_record.user_data_len;
+
+ memcpy(&(ee_new->record), &entry->record, sizeof(Eventlog_record));
+ memcpy(&(ee_new->data_record), &entry->data_record, sizeof(Eventlog_data_record));
+ ee_new->data = entry->data;
+
+ return ee_new;
}
-
-WERROR _eventlog_read_eventlog(pipes_struct *p,
- EVENTLOG_Q_READ_EVENTLOG *q_u,
- EVENTLOG_R_READ_EVENTLOG *r_u)
+
+/********************************************************************
+********************************************************************/
+
+static BOOL add_record_to_resp(EVENTLOG_R_READ_EVENTLOG *r_u, Eventlog_entry *ee_new)
{
- Eventlog_info *info = NULL;
- POLICY_HND *handle;
- Eventlog_entry entry, *ee_new;
- BOOL eof = False, eor = False;
- const char *direction = "";
- uint32 num_records_read = 0;
- prs_struct *ps;
- int numlines, i;
- char **buffer;
-
- if(!q_u || !r_u)
- return WERR_NOMEM;
-
- handle = &(q_u->handle);
- info = find_eventlog_info_by_hnd(p, handle);
- info->flags = q_u->flags;
- ps = &p->out_data.rdata;
- /* if this is the first time we're reading on this handle */
- if(info->active_entry == 0)
- {
- /* Rather than checking the EVENTLOG_SEQUENTIAL_READ/EVENTLOG_SEEK_READ flags,
- we'll just go to the offset specified in the request, or the oldest entry
- if no offset is specified */
- if(q_u->offset > 0)
- info->active_entry = q_u->offset;
- else
- info->active_entry = info->oldest_entry;
-
- }
-
- if(q_u->flags & EVENTLOG_FORWARDS_READ)
- direction = "forward";
- else if(q_u->flags & EVENTLOG_BACKWARDS_READ)
- direction = "backward";
-
- if(!(_eventlog_read_eventlog_hook(info, &entry, direction, info->active_entry, q_u->max_read_size, &eof, &buffer, &numlines)))
- {
- if(eof == False)
- return WERR_NOMEM;
- }
- if(numlines > 0)
- {
- ZERO_STRUCT(entry);
- for(i = 0; i < numlines; i++)
- {
- num_records_read = r_u->num_records;
- DEBUGADD(10, ("Line[%d] = [%s]\n", i, buffer[i]));
- _eventlog_read_parse_line(buffer[i], &entry, &eor);
- if(eor == True)
- {
- /* package ee_new entry */
- if((ee_new = _eventlog_read_package_entry(ps, q_u, r_u, &entry)) == NULL)
- {
- free(buffer);
- return WERR_NOMEM;
- }
- /* Now see if there is enough room to add */
- if(r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size)
- {
- r_u->bytes_in_next_record = ee_new->record.length;
- /* response would be too big to fit in client-size buffer */
- break;
+ Eventlog_entry *insert_point;
+
+ insert_point=r_u->entry;
+
+ if (NULL == insert_point) {
+ r_u->entry = ee_new;
+ ee_new->next = NULL;
+ } else {
+ while ((NULL != insert_point->next)) {
+ insert_point=insert_point->next;
}
- _eventlog_add_record_to_resp(r_u, ee_new);
- ZERO_STRUCT(entry);
- eor=False;
- num_records_read = r_u->num_records - num_records_read;
- DEBUG(10, ("_eventlog_read_eventlog: read [%d] records for a total of [%d] records using [%d] bytes out of a max of [%d].\n",
- num_records_read,
- r_u->num_records,
- r_u->num_bytes_in_resp,
- q_u->max_read_size));
- /* update the active record */
- if(info->flags & EVENTLOG_FORWARDS_READ)
- info->active_entry += num_records_read;
- else if(info->flags & EVENTLOG_BACKWARDS_READ)
- info->active_entry -= num_records_read;
- }
- }
- free(buffer);
- }
-
- return WERR_OK;
+ ee_new->next = NULL;
+ insert_point->next = ee_new;
+ }
+ r_u->num_records++;
+ r_u->num_bytes_in_resp += ee_new->record.length;
+
+ return True;
}
+
+/********************************************************************
+********************************************************************/
+
/**
* Callout to clear (and optionally backup) a specified event log
*
@@ -902,96 +741,224 @@ WERROR _eventlog_read_eventlog(pipes_struct *p,
* The given log is copied to that location on the server. See comments for
* eventlog_io_q_clear_eventlog for info about odd file name behavior
*/
-static BOOL _eventlog_clear_eventlog_hook(Eventlog_info *info,
- pstring backup_file_name)
+
+static BOOL clear_eventlog_hook(EventlogInfo *info, pstring backup_file_name)
{
- char *cmd = lp_eventlog_clear_cmd();
- char **qlines;
- pstring command;
- int numlines = 0;
- int ret;
- int fd = -1;
-
- if(cmd == NULL || strlen(cmd) == 0)
- {
- DEBUG(0, ("Must define an \"eventlog clear command\" entry in the config.\n"));
- return False;
- }
-
- memset(command, 0, sizeof(command));
- if(strlen(backup_file_name) > 0)
- slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\" \"%s\"",
- cmd,
- info->source_log_file_name,
- backup_file_name,
- info->handle_string);
- else
- slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\"",
- cmd,
- info->source_log_file_name,
- info->handle_string);
-
- DEBUG(10, ("Running [%s]\n", command));
- ret = smbrun(command, &fd);
- DEBUGADD(10, ("returned [%d]\n", ret));
-
- if(ret != 0)
- {
- if(fd != -1)
- close(fd);
- return False;
- }
+ char *cmd = lp_eventlog_clear_cmd();
+ char **qlines;
+ pstring command;
+ int numlines = 0;
+ int ret;
+ int fd = -1;
+
+ if ( !cmd || !*cmd ) {
+ DEBUG(0, ("Must define an \"eventlog clear command\" entry in the config.\n"));
+ return False;
+ }
+
+ if ( strlen(backup_file_name) )
+ pstr_sprintf( command, "%s \"%s\" \"%s\"", cmd, info->logname, backup_file_name );
+ else
+ pstr_sprintf( command, "%s \"%s\"", cmd, info->logname );
+
+ DEBUG(10, ("Running [%s]\n", command));
+ ret = smbrun(command, &fd);
+ DEBUGADD(10, ("returned [%d]\n", ret));
- qlines = fd_lines_load(fd, &numlines);
- DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
- close(fd);
+ if(ret != 0) {
+ if(fd != -1) {
+ close(fd);
+ }
+ return False;
+ }
- if(numlines)
- {
- DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
- if(0 == strncmp(qlines[0], "SUCCESS", strlen("SUCCESS")))
- {
- DEBUGADD(10, ("Able to clear [%s].\n", info->source_log_file_name));
- file_lines_free(qlines);
- return True;
+ qlines = fd_lines_load(fd, &numlines);
+ DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
+ close(fd);
+
+ if(numlines) {
+ DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
+ if(0 == strncmp(qlines[0], "SUCCESS", strlen("SUCCESS"))) {
+ DEBUGADD(10, ("Able to clear [%s].\n", info->logname));
+ file_lines_free(qlines);
+ return True;
+ }
}
- }
- file_lines_free(qlines);
- return False;
+ file_lines_free(qlines);
+ return False;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+WERROR _eventlog_open_eventlog(pipes_struct *p, EVENTLOG_Q_OPEN_EVENTLOG *q_u, EVENTLOG_R_OPEN_EVENTLOG *r_u)
+{
+ EventlogInfo *info = NULL;
+ fstring str;
+
+ if ( !(info = TALLOC_ZERO_P(NULL, EventlogInfo)) )
+ return WERR_NOMEM;
+
+ fstrcpy( str, global_myname() );
+ if ( q_u->servername.string ) {
+ rpcstr_pull( str, q_u->servername.string->buffer,
+ sizeof(str), q_u->servername.string->uni_str_len*2, 0 );
+ }
+ info->servername = talloc_strdup( info, str );
+
+ fstrcpy( str, "Application" );
+ if ( q_u->logname.string ) {
+ rpcstr_pull( str, q_u->logname.string->buffer,
+ sizeof(str), q_u->logname.string->uni_str_len*2, 0 );
+ }
+ info->logname = talloc_strdup( info, str );
+
+ DEBUG(10, ("_eventlog_open_eventlog: Using [%s] as the server name.\n", info->servername));
+ DEBUG(10, ("_eventlog_open_eventlog: Using [%s] as the source log file.\n", info->logname));
+
+ if ( !create_policy_hnd(p, &r_u->handle, free_eventlog_info, (void *)info) ) {
+ free_eventlog_info(info);
+ return WERR_NOMEM;
+ }
+
+ if ( !(open_eventlog_hook(info)) ) {
+ close_policy_hnd(p, &r_u->handle);
+ return WERR_BADFILE;
+ }
+
+ return WERR_OK;
}
-WERROR _eventlog_clear_eventlog(pipes_struct *p,
- EVENTLOG_Q_CLEAR_EVENTLOG *q_u,
- EVENTLOG_R_CLEAR_EVENTLOG *r_u)
+/********************************************************************
+********************************************************************/
+
+WERROR _eventlog_clear_eventlog(pipes_struct *p, EVENTLOG_Q_CLEAR_EVENTLOG *q_u, EVENTLOG_R_CLEAR_EVENTLOG *r_u)
{
- Eventlog_info *info = NULL;
- pstring backup_file_name;
- POLICY_HND *handle = NULL;
+ EventlogInfo *info = find_eventlog_info_by_hnd(p, &q_u->handle);
+ pstring backup_file_name;
- if(!q_u || !r_u)
- return WERR_NOMEM;
+ pstrcpy( backup_file_name, "" );
- handle = &(q_u->handle);
- info = find_eventlog_info_by_hnd(p, handle);
- memset(backup_file_name, 0, sizeof(backup_file_name));
+ if ( q_u->backupfile.string )
+ unistr2_to_ascii(backup_file_name, q_u->backupfile.string, sizeof(backup_file_name));
- if(q_u->backup_file_ptr != 0)
- {
- unistr2_to_ascii(backup_file_name, &(q_u->backup_file), sizeof(backup_file_name));
DEBUG(10, ("_eventlog_clear_eventlog: Using [%s] as the backup file name for log [%s].",
- backup_file_name,
- info->source_log_file_name));
- }
- else
- {
- /* if backup_file == NULL, do not back up the log before clearing it */
- DEBUG(10, ("_eventlog_clear_eventlog: clearing [%s] log without making a backup.",
- info->source_log_file_name));
- }
-
- if(!(_eventlog_clear_eventlog_hook(info, backup_file_name)))
- return WERR_BADFILE;
-
- return WERR_OK;
+ backup_file_name, info->logname));
+
+ if ( !(clear_eventlog_hook(info, backup_file_name)) )
+ return WERR_BADFILE;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _eventlog_close_eventlog(pipes_struct *p, EVENTLOG_Q_CLOSE_EVENTLOG *q_u, EVENTLOG_R_CLOSE_EVENTLOG *r_u)
+{
+ EventlogInfo *info = find_eventlog_info_by_hnd(p,&q_u->handle);
+
+ if ( !(close_eventlog_hook(info)) )
+ return WERR_BADFILE;
+
+ if ( !(close_policy_hnd(p, &q_u->handle)) ) {
+ return WERR_BADFID;
+ }
+
+ return WERR_OK;
}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _eventlog_read_eventlog(pipes_struct *p, EVENTLOG_Q_READ_EVENTLOG *q_u, EVENTLOG_R_READ_EVENTLOG *r_u)
+{
+ EventlogInfo *info = find_eventlog_info_by_hnd(p, &q_u->handle);
+ Eventlog_entry entry, *ee_new;
+ BOOL eof = False, eor = False;
+ const char *direction = "";
+ uint32 num_records_read = 0;
+ prs_struct *ps;
+ int numlines, i;
+ char **buffer;
+
+ info->flags = q_u->flags;
+ ps = &p->out_data.rdata;
+
+ if ( info->flags & EVENTLOG_FORWARDS_READ )
+ direction = "forward";
+ else if ( info->flags & EVENTLOG_BACKWARDS_READ )
+ direction = "backward";
+
+ if ( !(read_eventlog_hook(info, &entry, direction, q_u->offset, q_u->max_read_size, &eof, &buffer, &numlines)) ) {
+ if(eof == False) {
+ return WERR_NOMEM;
+ }
+ }
+
+ if(numlines > 0) {
+ ZERO_STRUCT(entry);
+ for(i = 0; i < numlines; i++) {
+ num_records_read = r_u->num_records;
+ DEBUGADD(10, ("Line[%d] = [%s]\n", i, buffer[i]));
+ parse_logentry(buffer[i], &entry, &eor);
+ if(eor == True) {
+ /* package ee_new entry */
+ if((ee_new = read_package_entry(ps, q_u, r_u, &entry)) == NULL) {
+ SAFE_FREE(buffer);
+ return WERR_NOMEM;
+ }
+ /* Now see if there is enough room to add */
+ if(r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size) {
+ r_u->bytes_in_next_record = ee_new->record.length;
+ /* response would be too big to fit in client-size buffer */
+ break;
+ }
+ add_record_to_resp(r_u, ee_new);
+ ZERO_STRUCT(entry);
+ eor=False;
+ num_records_read = r_u->num_records - num_records_read;
+ DEBUG(10, ("_eventlog_read_eventlog: read [%d] records for a total of [%d] records using [%d] bytes out of a max of [%d].\n",
+ num_records_read,
+ r_u->num_records,
+ r_u->num_bytes_in_resp,
+ q_u->max_read_size));
+ }
+ }
+ SAFE_FREE(buffer);
+ }
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _eventlog_get_oldest_entry(pipes_struct *p, EVENTLOG_Q_GET_OLDEST_ENTRY *q_u, EVENTLOG_R_GET_OLDEST_ENTRY *r_u)
+{
+ EventlogInfo *info = find_eventlog_info_by_hnd(p, &q_u->handle);
+
+ if ( !(get_oldest_entry_hook(info)) )
+ return WERR_BADFILE;
+
+ r_u->oldest_entry = info->oldest_entry;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _eventlog_get_num_records(pipes_struct *p, EVENTLOG_Q_GET_NUM_RECORDS *q_u, EVENTLOG_R_GET_NUM_RECORDS *r_u)
+{
+ EventlogInfo *info = find_eventlog_info_by_hnd(p, &q_u->handle);
+
+ if ( !(get_num_records_hook(info)) )
+ return WERR_BADFILE;
+
+ r_u->num_records = info->num_records;
+
+ return WERR_OK;
+}
+
diff --git a/source3/rpc_server/srv_lsa_hnd.c b/source3/rpc_server/srv_lsa_hnd.c
index 68072b528aa..7da87d5b93d 100644
--- a/source3/rpc_server/srv_lsa_hnd.c
+++ b/source3/rpc_server/srv_lsa_hnd.c
@@ -253,16 +253,18 @@ BOOL pipe_access_check(pipes_struct *p)
user_struct *user = get_valid_user_struct(p->vuid);
/* schannel, so we must be ok */
- if (p->netsec_auth_validated)
+ if (p->pipe_bound && (p->auth.auth_type == PIPE_AUTH_TYPE_SCHANNEL)) {
return True;
+ }
if (!user) {
DEBUG(3, ("invalid vuid %d\n", p->vuid));
return False;
}
- if (user->guest)
+ if (user->guest) {
return False;
+ }
}
return True;
diff --git a/source3/rpc_server/srv_lsa_nt.c b/source3/rpc_server/srv_lsa_nt.c
index 021f1dc8e0f..15d420538ef 100644
--- a/source3/rpc_server/srv_lsa_nt.c
+++ b/source3/rpc_server/srv_lsa_nt.c
@@ -805,17 +805,12 @@ NTSTATUS _lsa_enum_privs(pipes_struct *p, LSA_Q_ENUM_PRIVS *q_u, LSA_R_ENUM_PRIV
struct lsa_info *handle;
uint32 i;
uint32 enum_context = q_u->enum_context;
- int num_privs = 0;
+ int num_privs = count_all_privileges();
LSA_PRIV_ENTRY *entries = NULL;
LUID_ATTR luid;
/* remember that the enum_context starts at 0 and not 1 */
- if ( lp_enable_privileges() )
- num_privs = count_all_privileges();
- else
- DEBUG(2,("_lsa_enum_privs: client trying to enumerate privileges by not enabled in smb.conf!\n"));
-
if ( enum_context >= num_privs )
return NT_STATUS_NO_MORE_ENTRIES;
diff --git a/source3/rpc_server/srv_netlog_nt.c b/source3/rpc_server/srv_netlog_nt.c
index 15827a8b55e..5aefe3ca3c9 100644
--- a/source3/rpc_server/srv_netlog_nt.c
+++ b/source3/rpc_server/srv_netlog_nt.c
@@ -74,6 +74,7 @@ NTSTATUS _net_logon_ctrl(pipes_struct *p, NET_Q_LOGON_CTRL *q_u,
/****************************************************************************
Send a message to smbd to do a sam synchronisation
**************************************************************************/
+
static void send_sync_message(void)
{
TDB_CONTEXT *tdb;
@@ -268,26 +269,33 @@ static BOOL get_md4pw(char *md4pw, char *mach_acct)
NTSTATUS _net_req_chal(pipes_struct *p, NET_Q_REQ_CHAL *q_u, NET_R_REQ_CHAL *r_u)
{
- NTSTATUS status = NT_STATUS_OK;
-
- rpcstr_pull(p->dc.remote_machine,q_u->uni_logon_clnt.buffer,sizeof(fstring),q_u->uni_logon_clnt.uni_str_len*2,0);
-
- /* create a server challenge for the client */
- /* Set these to random values. */
- generate_random_buffer(p->dc.srv_chal.data, 8);
-
- memcpy(p->dc.srv_cred.challenge.data, p->dc.srv_chal.data, 8);
+ if (!p->dc) {
+ p->dc = TALLOC_ZERO_P(p->pipe_state_mem_ctx, struct dcinfo);
+ if (!p->dc) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ DEBUG(10,("_net_req_chal: new challenge requested. Clearing old state.\n"));
+ ZERO_STRUCTP(p->dc);
+ }
- memcpy(p->dc.clnt_chal.data , q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
- memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
+ rpcstr_pull(p->dc->remote_machine,
+ q_u->uni_logon_clnt.buffer,
+ sizeof(fstring),q_u->uni_logon_clnt.uni_str_len*2,0);
- memset((char *)p->dc.sess_key, '\0', sizeof(p->dc.sess_key));
+ /* Save the client challenge to the server. */
+ memcpy(p->dc->clnt_chal.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
- p->dc.challenge_sent = True;
+ /* Create a server challenge for the client */
+ /* Set this to a random value. */
+ generate_random_buffer(p->dc->srv_chal.data, 8);
+
/* set up the LSA REQUEST CHALLENGE response */
- init_net_r_req_chal(r_u, &p->dc.srv_chal, status);
+ init_net_r_req_chal(r_u, &p->dc->srv_chal, NT_STATUS_OK);
- return status;
+ p->dc->challenge_sent = True;
+
+ return NT_STATUS_OK;
}
/*************************************************************************
@@ -301,50 +309,54 @@ static void init_net_r_auth(NET_R_AUTH *r_a, DOM_CHAL *resp_cred, NTSTATUS statu
}
/*************************************************************************
- _net_auth
+ _net_auth. Create the initial credentials.
*************************************************************************/
NTSTATUS _net_auth(pipes_struct *p, NET_Q_AUTH *q_u, NET_R_AUTH *r_u)
{
- NTSTATUS status = NT_STATUS_OK;
- DOM_CHAL srv_cred;
- UTIME srv_time;
fstring mach_acct;
+ fstring remote_machine;
+ DOM_CHAL srv_chal_out;
- srv_time.time = 0;
-
- rpcstr_pull(mach_acct, q_u->clnt_id.uni_acct_name.buffer,sizeof(fstring),q_u->clnt_id.uni_acct_name.uni_str_len*2,0);
+ if (!p->dc || !p->dc->challenge_sent) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
- if (p->dc.challenge_sent && get_md4pw((char *)p->dc.md4pw, mach_acct)) {
+ rpcstr_pull(mach_acct, q_u->clnt_id.uni_acct_name.buffer,sizeof(fstring),
+ q_u->clnt_id.uni_acct_name.uni_str_len*2,0);
+ rpcstr_pull(remote_machine, q_u->clnt_id.uni_comp_name.buffer,sizeof(fstring),
+ q_u->clnt_id.uni_comp_name.uni_str_len*2,0);
- /* from client / server challenges and md4 password, generate sess key */
- cred_session_key(&p->dc.clnt_chal, &p->dc.srv_chal,
- p->dc.md4pw, p->dc.sess_key);
-
- /* check that the client credentials are valid */
- if (cred_assert(&q_u->clnt_chal, p->dc.sess_key, &p->dc.clnt_cred.challenge, srv_time)) {
-
- /* create server challenge for inclusion in the reply */
- cred_create(p->dc.sess_key, &p->dc.srv_cred.challenge, srv_time, &srv_cred);
-
- /* copy the received client credentials for use next time */
- memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
- memcpy(p->dc.srv_cred .challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
-
- /* Save the machine account name. */
- fstrcpy(p->dc.mach_acct, mach_acct);
-
- p->dc.authenticated = True;
+ if (!get_md4pw((char *)p->dc->mach_pw, mach_acct)) {
+ DEBUG(0,("_net_auth: creds_server_check failed. Failed to "
+ "get pasword for machine account %s "
+ "from client %s\n",
+ mach_acct, remote_machine ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
- } else {
- status = NT_STATUS_ACCESS_DENIED;
- }
- } else {
- status = NT_STATUS_ACCESS_DENIED;
+ /* From the client / server challenges and md4 password, generate sess key */
+ creds_server_init(p->dc,
+ &p->dc->clnt_chal, /* Stored client chal. */
+ &p->dc->srv_chal, /* Stored server chal. */
+ p->dc->mach_pw,
+ &srv_chal_out);
+
+ /* Check client credentials are valid. */
+ if (!creds_server_check(p->dc, &q_u->clnt_chal)) {
+ DEBUG(0,("_net_auth: creds_server_check failed. Rejecting auth "
+ "request from client %s machine account %s\n",
+ remote_machine, mach_acct ));
+ return NT_STATUS_ACCESS_DENIED;
}
-
+
+ fstrcpy(p->dc->mach_acct, mach_acct);
+ fstrcpy(p->dc->remote_machine, remote_machine);
+ p->dc->authenticated = True;
+
/* set up the LSA AUTH response */
- init_net_r_auth(r_u, &srv_cred, status);
+ /* Return the server credentials. */
+ init_net_r_auth(r_u, &srv_chal_out, NT_STATUS_OK);
return r_u->status;
}
@@ -367,51 +379,54 @@ static void init_net_r_auth_2(NET_R_AUTH_2 *r_a,
NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
{
- NTSTATUS status = NT_STATUS_OK;
- DOM_CHAL srv_cred;
- UTIME srv_time;
NEG_FLAGS srv_flgs;
fstring mach_acct;
+ fstring remote_machine;
+ DOM_CHAL srv_chal_out;
- srv_time.time = 0;
+ rpcstr_pull(mach_acct, q_u->clnt_id.uni_acct_name.buffer,sizeof(fstring),
+ q_u->clnt_id.uni_acct_name.uni_str_len*2,0);
+ rpcstr_pull(remote_machine, q_u->clnt_id.uni_comp_name.buffer,sizeof(fstring),
+ q_u->clnt_id.uni_comp_name.uni_str_len*2,0);
+
+ if (!p->dc || !p->dc->challenge_sent) {
+ DEBUG(0,("_net_auth2: no challenge sent to client %s\n",
+ remote_machine ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
if ( (lp_server_schannel() == True) &&
((q_u->clnt_flgs.neg_flags & NETLOGON_NEG_SCHANNEL) == 0) ) {
/* schannel must be used, but client did not offer it. */
- status = NT_STATUS_ACCESS_DENIED;
+ DEBUG(0,("_net_auth2: schannel required but client failed "
+ "to offer it. Client was %s\n",
+ mach_acct ));
+ return NT_STATUS_ACCESS_DENIED;
}
- rpcstr_pull(mach_acct, q_u->clnt_id.uni_acct_name.buffer,sizeof(fstring),q_u->clnt_id.uni_acct_name.uni_str_len*2,0);
-
- if (p->dc.challenge_sent && get_md4pw((char *)p->dc.md4pw, mach_acct)) {
-
- /* from client / server challenges and md4 password, generate sess key */
- cred_session_key(&p->dc.clnt_chal, &p->dc.srv_chal,
- p->dc.md4pw, p->dc.sess_key);
-
- /* check that the client credentials are valid */
- if (cred_assert(&q_u->clnt_chal, p->dc.sess_key, &p->dc.clnt_cred.challenge, srv_time)) {
-
- /* create server challenge for inclusion in the reply */
- cred_create(p->dc.sess_key, &p->dc.srv_cred.challenge, srv_time, &srv_cred);
-
- /* copy the received client credentials for use next time */
- memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
- memcpy(p->dc.srv_cred .challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
-
- /* Save the machine account name. */
- fstrcpy(p->dc.mach_acct, mach_acct);
-
- p->dc.authenticated = True;
+ if (!get_md4pw((char *)p->dc->mach_pw, mach_acct)) {
+ DEBUG(0,("_net_auth2: failed to get machine password for "
+ "account %s\n",
+ mach_acct ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
- } else {
- status = NT_STATUS_ACCESS_DENIED;
- }
- } else {
- status = NT_STATUS_ACCESS_DENIED;
+ /* From the client / server challenges and md4 password, generate sess key */
+ creds_server_init(p->dc,
+ &p->dc->clnt_chal, /* Stored client chal. */
+ &p->dc->srv_chal, /* Stored server chal. */
+ p->dc->mach_pw,
+ &srv_chal_out);
+
+ /* Check client credentials are valid. */
+ if (!creds_server_check(p->dc, &q_u->clnt_chal)) {
+ DEBUG(0,("_net_auth2: creds_server_check failed. Rejecting auth "
+ "request from client %s machine account %s\n",
+ remote_machine, mach_acct ));
+ return NT_STATUS_ACCESS_DENIED;
}
-
+
srv_flgs.neg_flags = 0x000001ff;
if (lp_server_schannel() != False) {
@@ -419,12 +434,11 @@ NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
}
/* set up the LSA AUTH 2 response */
- init_net_r_auth_2(r_u, &srv_cred, &srv_flgs, status);
+ init_net_r_auth_2(r_u, &srv_chal_out, &srv_flgs, NT_STATUS_OK);
- if (NT_STATUS_IS_OK(status)) {
- server_auth2_negotiated = True;
- last_dcinfo = p->dc;
- }
+ server_auth2_negotiated = True;
+ p->dc->authenticated = True;
+ last_dcinfo = *p->dc;
return r_u->status;
}
@@ -436,32 +450,39 @@ NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *r_u)
{
NTSTATUS status = NT_STATUS_ACCESS_DENIED;
- DOM_CRED srv_cred;
- pstring workstation;
+ fstring workstation;
SAM_ACCOUNT *sampass=NULL;
BOOL ret = False;
unsigned char pwd[16];
int i;
uint32 acct_ctrl;
+ DOM_CRED cred_out;
const uchar *old_pw;
- /* checks and updates credentials. creates reply credentials */
- if (!(p->dc.authenticated && deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->clnt_id.cred, &srv_cred)))
+ if (!p->dc || !p->dc->authenticated) {
return NT_STATUS_INVALID_HANDLE;
+ }
- memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
+ /* Step the creds chain forward. */
+ if (!creds_server_step(p->dc, &q_u->clnt_id.cred, &cred_out)) {
+ DEBUG(0,("_net_srv_pwset: creds_server_step failed. Rejecting auth "
+ "request from client %s machine account %s\n",
+ p->dc->remote_machine, p->dc->mach_acct ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
rpcstr_pull(workstation,q_u->clnt_id.login.uni_comp_name.buffer,
sizeof(workstation),q_u->clnt_id.login.uni_comp_name.uni_str_len*2,0);
- DEBUG(3,("Server Password Set by Wksta:[%s] on account [%s]\n", workstation, p->dc.mach_acct));
+ DEBUG(3,("_net_srv_pwset: Server Password Set by Wksta:[%s] on account [%s]\n",
+ workstation, p->dc->mach_acct));
pdb_init_sam(&sampass);
become_root();
- ret=pdb_getsampwnam(sampass, p->dc.mach_acct);
+ ret=pdb_getsampwnam(sampass, p->dc->mach_acct);
unbecome_root();
/* Ensure the account exists and is a machine account. */
@@ -481,7 +502,8 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *
return NT_STATUS_ACCOUNT_DISABLED;
}
- cred_hash3( pwd, q_u->pwd, p->dc.sess_key, 0);
+ /* Woah - what does this to to the credential chain ? JRA */
+ cred_hash3( pwd, q_u->pwd, p->dc->sess_key, 0);
DEBUG(100,("Server password set : new given value was :\n"));
for(i = 0; i < sizeof(pwd); i++)
@@ -498,17 +520,17 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *
} else {
/* LM password should be NULL for machines */
- if (!pdb_set_lanman_passwd (sampass, NULL, PDB_CHANGED)) {
+ if (!pdb_set_lanman_passwd(sampass, NULL, PDB_CHANGED)) {
pdb_free_sam(&sampass);
return NT_STATUS_NO_MEMORY;
}
- if (!pdb_set_nt_passwd (sampass, pwd, PDB_CHANGED)) {
+ if (!pdb_set_nt_passwd(sampass, pwd, PDB_CHANGED)) {
pdb_free_sam(&sampass);
return NT_STATUS_NO_MEMORY;
}
- if (!pdb_set_pass_changed_now (sampass)) {
+ if (!pdb_set_pass_changed_now(sampass)) {
pdb_free_sam(&sampass);
/* Not quite sure what this one qualifies as, but this will do */
return NT_STATUS_UNSUCCESSFUL;
@@ -518,42 +540,41 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *
ret = pdb_update_sam_account (sampass);
unbecome_root();
}
- if (ret)
+ if (ret) {
status = NT_STATUS_OK;
+ }
/* set up the LSA Server Password Set response */
- init_net_r_srv_pwset(r_u, &srv_cred, status);
+ init_net_r_srv_pwset(r_u, &cred_out, status);
pdb_free_sam(&sampass);
return r_u->status;
}
-
/*************************************************************************
_net_sam_logoff:
*************************************************************************/
NTSTATUS _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
{
- DOM_CRED srv_cred;
-
if (!get_valid_user_struct(p->vuid))
return NT_STATUS_NO_SUCH_USER;
- /* checks and updates credentials. creates reply credentials */
- if (!(p->dc.authenticated && deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred,
- &q_u->sam_id.client.cred, &srv_cred)))
+ if (!p->dc || !p->dc->authenticated) {
return NT_STATUS_INVALID_HANDLE;
+ }
- /* what happens if we get a logoff for an unknown user? */
- memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
-
- /* XXXX maybe we want to say 'no', reject the client's credentials */
r_u->buffer_creds = 1; /* yes, we have valid server credentials */
- memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
- r_u->status = NT_STATUS_OK;
+ /* checks and updates credentials. creates reply credentials */
+ if (!creds_server_step(p->dc, &q_u->sam_id.client.cred, &r_u->srv_creds)) {
+ DEBUG(0,("_net_sam_logoff: creds_server_step failed. Rejecting auth "
+ "request from client %s machine account %s\n",
+ p->dc->remote_machine, p->dc->mach_acct ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ r_u->status = NT_STATUS_OK;
return r_u->status;
}
@@ -567,7 +588,6 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
NTSTATUS status = NT_STATUS_OK;
NET_USER_INFO_3 *usr_info = NULL;
NET_ID_INFO_CTR *ctr = q_u->sam_id.ctr;
- DOM_CRED srv_cred;
UNISTR2 *uni_samlogon_user = NULL;
UNISTR2 *uni_samlogon_domain = NULL;
UNISTR2 *uni_samlogon_workstation = NULL;
@@ -588,26 +608,31 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
r_u->switch_value = 0; /* indicates no info */
r_u->auth_resp = 1; /* authoritative response */
r_u->switch_value = 3; /* indicates type of validation user info */
+ r_u->buffer_creds = 1; /* Ensure we always return server creds. */
if (!get_valid_user_struct(p->vuid))
return NT_STATUS_NO_SUCH_USER;
+ if (!p->dc || !p->dc->authenticated) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
- if ( (lp_server_schannel() == True) && (!p->netsec_auth_validated) ) {
+ if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
/* 'server schannel = yes' should enforce use of
schannel, the client did offer it in auth2, but
obviously did not use it. */
+ DEBUG(0,("_net_sam_logoff: client %s not using schannel for netlogon\n",
+ p->dc->remote_machine ));
return NT_STATUS_ACCESS_DENIED;
}
/* checks and updates credentials. creates reply credentials */
- if (!(p->dc.authenticated && deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred)))
- return NT_STATUS_INVALID_HANDLE;
-
- memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
-
- r_u->buffer_creds = 1; /* yes, we have valid server credentials */
- memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
+ if (!creds_server_step(p->dc, &q_u->sam_id.client.cred, &r_u->srv_creds)) {
+ DEBUG(0,("_net_sam_logoff: creds_server_step failed. Rejecting auth "
+ "request from client %s machine account %s\n",
+ p->dc->remote_machine, p->dc->mach_acct ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
/* find the username */
@@ -692,7 +717,7 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
nt_workstation, chal,
ctr->auth.id1.lm_owf.data,
ctr->auth.id1.nt_owf.data,
- p->dc.sess_key)) {
+ p->dc->sess_key)) {
status = NT_STATUS_NO_MEMORY;
}
break;
@@ -791,7 +816,7 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
}
ZERO_STRUCT(netlogon_sess_key);
- memcpy(netlogon_sess_key, p->dc.sess_key, 8);
+ memcpy(netlogon_sess_key, p->dc->sess_key, 8);
if (server_info->user_session_key.length) {
memcpy(user_session_key, server_info->user_session_key.data,
MIN(sizeof(user_session_key), server_info->user_session_key.length));
diff --git a/source3/rpc_server/srv_ntsvcs.c b/source3/rpc_server/srv_ntsvcs.c
new file mode 100644
index 00000000000..48910dbee2e
--- /dev/null
+++ b/source3/rpc_server/srv_ntsvcs.c
@@ -0,0 +1,220 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Gerald Carter 2005.
+ *
+ * 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"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+/*******************************************************************
+ ********************************************************************/
+
+static BOOL api_ntsvcs_get_version(pipes_struct *p)
+{
+ NTSVCS_Q_GET_VERSION q_u;
+ NTSVCS_R_GET_VERSION r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!ntsvcs_io_q_get_version("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _ntsvcs_get_version(p, &q_u, &r_u);
+
+ if(!ntsvcs_io_r_get_version("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static BOOL api_ntsvcs_get_device_list_size(pipes_struct *p)
+{
+ NTSVCS_Q_GET_DEVICE_LIST_SIZE q_u;
+ NTSVCS_R_GET_DEVICE_LIST_SIZE r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!ntsvcs_io_q_get_device_list_size("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _ntsvcs_get_device_list_size(p, &q_u, &r_u);
+
+ if(!ntsvcs_io_r_get_device_list_size("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static BOOL api_ntsvcs_get_device_list(pipes_struct *p)
+{
+ NTSVCS_Q_GET_DEVICE_LIST q_u;
+ NTSVCS_R_GET_DEVICE_LIST r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!ntsvcs_io_q_get_device_list("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _ntsvcs_get_device_list(p, &q_u, &r_u);
+
+ if(!ntsvcs_io_r_get_device_list("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static BOOL api_ntsvcs_validate_device_instance(pipes_struct *p)
+{
+ NTSVCS_Q_VALIDATE_DEVICE_INSTANCE q_u;
+ NTSVCS_R_VALIDATE_DEVICE_INSTANCE r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!ntsvcs_io_q_validate_device_instance("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _ntsvcs_validate_device_instance(p, &q_u, &r_u);
+
+ if(!ntsvcs_io_r_validate_device_instance("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static BOOL api_ntsvcs_get_device_reg_property(pipes_struct *p)
+{
+ NTSVCS_Q_GET_DEVICE_REG_PROPERTY q_u;
+ NTSVCS_R_GET_DEVICE_REG_PROPERTY r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!ntsvcs_io_q_get_device_reg_property("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _ntsvcs_get_device_reg_property(p, &q_u, &r_u);
+
+ if(!ntsvcs_io_r_get_device_reg_property("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static BOOL api_ntsvcs_get_hw_profile_info(pipes_struct *p)
+{
+ NTSVCS_Q_GET_HW_PROFILE_INFO q_u;
+ NTSVCS_R_GET_HW_PROFILE_INFO r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!ntsvcs_io_q_get_hw_profile_info("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _ntsvcs_get_hw_profile_info(p, &q_u, &r_u);
+
+ if(!ntsvcs_io_r_get_hw_profile_info("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+static BOOL api_ntsvcs_hw_profile_flags(pipes_struct *p)
+{
+ NTSVCS_Q_HW_PROFILE_FLAGS q_u;
+ NTSVCS_R_HW_PROFILE_FLAGS r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!ntsvcs_io_q_hw_profile_flags("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _ntsvcs_hw_profile_flags(p, &q_u, &r_u);
+
+ if(!ntsvcs_io_r_hw_profile_flags("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ \PIPE\svcctl commands
+ ********************************************************************/
+
+static struct api_struct api_ntsvcs_cmds[] =
+{
+ { "NTSVCS_GET_VERSION" , NTSVCS_GET_VERSION , api_ntsvcs_get_version },
+ { "NTSVCS_GET_DEVICE_LIST_SIZE" , NTSVCS_GET_DEVICE_LIST_SIZE , api_ntsvcs_get_device_list_size },
+ { "NTSVCS_GET_DEVICE_LIST" , NTSVCS_GET_DEVICE_LIST , api_ntsvcs_get_device_list },
+ { "NTSVCS_VALIDATE_DEVICE_INSTANCE" , NTSVCS_VALIDATE_DEVICE_INSTANCE , api_ntsvcs_validate_device_instance },
+ { "NTSVCS_GET_DEVICE_REG_PROPERTY" , NTSVCS_GET_DEVICE_REG_PROPERTY , api_ntsvcs_get_device_reg_property },
+ { "NTSVCS_GET_HW_PROFILE_INFO" , NTSVCS_GET_HW_PROFILE_INFO , api_ntsvcs_get_hw_profile_info },
+ { "NTSVCS_HW_PROFILE_FLAGS" , NTSVCS_HW_PROFILE_FLAGS , api_ntsvcs_hw_profile_flags }
+};
+
+
+void ntsvcs_get_pipe_fns( struct api_struct **fns, int *n_fns )
+{
+ *fns = api_ntsvcs_cmds;
+ *n_fns = sizeof(api_ntsvcs_cmds) / sizeof(struct api_struct);
+}
+
+NTSTATUS rpc_ntsvcs_init(void)
+{
+ return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "ntsvcs", "ntsvcs", api_ntsvcs_cmds,
+ sizeof(api_ntsvcs_cmds) / sizeof(struct api_struct));
+}
diff --git a/source3/rpc_server/srv_ntsvcs_nt.c b/source3/rpc_server/srv_ntsvcs_nt.c
new file mode 100644
index 00000000000..0bb9154aaf0
--- /dev/null
+++ b/source3/rpc_server/srv_ntsvcs_nt.c
@@ -0,0 +1,174 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ *
+ * Copyright (C) Gerald (Jerry) Carter 2005.
+ *
+ * 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"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+/********************************************************************
+********************************************************************/
+
+static char* get_device_path( const char *device )
+{
+ static pstring path;
+
+ pstr_sprintf( path, "ROOT\\Legacy_%s\\0000", device );
+
+ return path;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _ntsvcs_get_version( pipes_struct *p, NTSVCS_Q_GET_VERSION *q_u, NTSVCS_R_GET_VERSION *r_u )
+{
+ r_u->version = 0x00000400; /* no idea what this means */
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _ntsvcs_get_device_list_size( pipes_struct *p, NTSVCS_Q_GET_DEVICE_LIST_SIZE *q_u, NTSVCS_R_GET_DEVICE_LIST_SIZE *r_u )
+{
+ fstring device;
+ const char *devicepath;
+
+ if ( !q_u->devicename )
+ return WERR_ACCESS_DENIED;
+
+ rpcstr_pull(device, q_u->devicename->buffer, sizeof(device), q_u->devicename->uni_str_len*2, 0);
+ devicepath = get_device_path( device );
+
+ r_u->size = strlen(devicepath) + 2;
+
+ return WERR_OK;
+}
+
+
+/********************************************************************
+********************************************************************/
+
+WERROR _ntsvcs_get_device_list( pipes_struct *p, NTSVCS_Q_GET_DEVICE_LIST *q_u, NTSVCS_R_GET_DEVICE_LIST *r_u )
+{
+ fstring device;
+ const char *devicepath;
+
+ if ( !q_u->devicename )
+ return WERR_ACCESS_DENIED;
+
+ rpcstr_pull(device, q_u->devicename->buffer, sizeof(device), q_u->devicename->uni_str_len*2, 0);
+ devicepath = get_device_path( device );
+
+ /* From the packet traces I've see, I think this really should be an array
+ of UNISTR2's. But I've never seen more than one string in spite of the
+ fact that the string in double NULL terminated. -- jerry */
+
+ init_unistr2( &r_u->devicepath, devicepath, UNI_STR_TERMINATE );
+ r_u->needed = r_u->devicepath.uni_str_len;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _ntsvcs_get_device_reg_property( pipes_struct *p, NTSVCS_Q_GET_DEVICE_REG_PROPERTY *q_u, NTSVCS_R_GET_DEVICE_REG_PROPERTY *r_u )
+{
+ fstring devicepath;
+ char *ptr;
+ REGVAL_CTR *values;
+ REGISTRY_VALUE *val;
+
+ rpcstr_pull(devicepath, q_u->devicepath.buffer, sizeof(devicepath), q_u->devicepath.uni_str_len*2, 0);
+
+ switch( q_u->property ) {
+ case DEV_REGPROP_DESC:
+ /* just parse the service name from the device path and then
+ lookup the display name */
+ if ( !(ptr = strrchr_m( devicepath, '\\' )) )
+ return WERR_GENERAL_FAILURE;
+ *ptr = '\0';
+
+ if ( !(ptr = strrchr_m( devicepath, '_' )) )
+ return WERR_GENERAL_FAILURE;
+ ptr++;
+
+ if ( !(values = svcctl_fetch_regvalues( ptr, p->pipe_user.nt_user_token )) )
+ return WERR_GENERAL_FAILURE;
+
+ if ( !(val = regval_ctr_getvalue( values, "DisplayName" )) ) {
+ TALLOC_FREE( values );
+ return WERR_GENERAL_FAILURE;
+ }
+
+ r_u->unknown1 = 0x1; /* always 1...tested using a remove device manager connection */
+ r_u->size = reg_init_regval_buffer( &r_u->value, val );
+ r_u->needed = r_u->size;
+
+ TALLOC_FREE(values);
+
+ break;
+
+ default:
+ r_u->unknown1 = 0x00437c98;
+ return WERR_CM_NO_SUCH_VALUE;
+ }
+
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _ntsvcs_validate_device_instance( pipes_struct *p, NTSVCS_Q_VALIDATE_DEVICE_INSTANCE *q_u, NTSVCS_R_VALIDATE_DEVICE_INSTANCE *r_u )
+{
+ /* whatever dude */
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _ntsvcs_get_hw_profile_info( pipes_struct *p, NTSVCS_Q_GET_HW_PROFILE_INFO *q_u, NTSVCS_R_GET_HW_PROFILE_INFO *r_u )
+{
+ /* steal the incoming buffer */
+
+ r_u->buffer_size = q_u->buffer_size;
+ r_u->buffer = q_u->buffer;
+
+ /* Take the 5th Ammentment */
+
+ return WERR_CM_NO_MORE_HW_PROFILES;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _ntsvcs_hw_profile_flags( pipes_struct *p, NTSVCS_Q_HW_PROFILE_FLAGS *q_u, NTSVCS_R_HW_PROFILE_FLAGS *r_u )
+{
+ /* just nod your head */
+
+ return WERR_OK;
+}
+
diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
index 63e8d2f5cda..ba6d9704e80 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -1,11 +1,7 @@
/*
* Unix SMB/CIFS implementation.
* 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,
- * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003.
+ * Almost completely rewritten by (C) Jeremy Allison 2005.
*
* 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
@@ -30,12 +26,6 @@
* and DCE/RPC, while minimising the amount of mallocs, unnecessary
* data copies, and network traffic.
*
- * in this version, which takes a "let's learn what's going on and
- * get something running" approach, there is additional network
- * traffic generated, but the code should be easier to understand...
- *
- * ... if you read the docs. or stare at packets for weeks on end.
- *
*/
#include "includes.h"
@@ -51,52 +41,38 @@ extern struct current_user current_user;
We need to transfer the session key from one rpc bind to the
next. This is the way the netlogon schannel works.
**************************************************************/
+
struct dcinfo last_dcinfo;
BOOL server_auth2_negotiated = False;
-static void NTLMSSPcalc_p( pipes_struct *p, unsigned char *data, int len)
+static void free_pipe_ntlmssp_auth_data(struct pipe_auth_data *auth)
{
- unsigned char *hash = p->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;
+ AUTH_NTLMSSP_STATE *a = auth->a_u.auth_ntlmssp_state;
- 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];
+ if (a) {
+ auth_ntlmssp_end(&a);
}
-
- hash[256] = index_i;
- hash[257] = index_j;
+ auth->a_u.auth_ntlmssp_state = NULL;
}
/*******************************************************************
Generate the next PDU to be returned from the data in p->rdata.
- We cheat here as this function doesn't handle the special auth
- footers of the authenticated bind response reply.
+ Handle NTLMSSP.
********************************************************************/
-BOOL create_next_pdu(pipes_struct *p)
+static BOOL create_next_pdu_ntlmssp(pipes_struct *p)
{
RPC_HDR_RESP hdr_resp;
- BOOL auth_verify = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) != 0);
- BOOL auth_seal = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SEAL) != 0);
uint32 ss_padding_len = 0;
- uint32 data_len;
uint32 data_space_available;
uint32 data_len_left;
+ uint32 data_len;
prs_struct outgoing_pdu;
- uint32 data_pos;
+ NTSTATUS status;
+ DATA_BLOB auth_blob;
+ RPC_HDR_AUTH auth_info;
+ uint8 auth_type, auth_level;
+ AUTH_NTLMSSP_STATE *a = p->auth.a_u.auth_ntlmssp_state;
/*
* If we're in the fault state, keep returning fault PDU's until
@@ -124,18 +100,6 @@ BOOL create_next_pdu(pipes_struct *p)
* Work out how much we can fit in a single PDU.
*/
- data_space_available = sizeof(p->out_data.current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;
- if(p->ntlmssp_auth_validated) {
- data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN);
- } else if(p->netsec_auth_validated) {
- data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN);
- }
-
- /*
- * The amount we send is the minimum of the available
- * space and the amount left to send.
- */
-
data_len_left = prs_offset(&p->out_data.rdata) - p->out_data.data_sent_length;
/*
@@ -143,10 +107,18 @@ BOOL create_next_pdu(pipes_struct *p)
*/
if(!data_len_left) {
- DEBUG(0,("create_next_pdu: no data left to send !\n"));
+ DEBUG(0,("create_next_pdu_ntlmssp: no data left to send !\n"));
return False;
}
+ data_space_available = sizeof(p->out_data.current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN -
+ RPC_HDR_AUTH_LEN - NTLMSSP_SIG_SIZE;
+
+ /*
+ * The amount we send is the minimum of the available
+ * space and the amount left to send.
+ */
+
data_len = MIN(data_len_left, data_space_available);
/*
@@ -162,9 +134,9 @@ BOOL create_next_pdu(pipes_struct *p)
if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) {
p->hdr.flags |= RPC_FLG_LAST;
- if ((auth_seal || auth_verify || p->netsec_auth_validated) && (data_len_left % 8)) {
+ if (data_len_left % 8) {
ss_padding_len = 8 - (data_len_left % 8);
- DEBUG(10,("create_next_pdu: adding sign/seal padding of %u\n",
+ DEBUG(10,("create_next_pdu_ntlmssp: adding sign/seal padding of %u\n",
ss_padding_len ));
}
}
@@ -173,20 +145,11 @@ BOOL create_next_pdu(pipes_struct *p)
* Set up the header lengths.
*/
- if (p->ntlmssp_auth_validated) {
- p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN +
- data_len + ss_padding_len +
- RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN;
- p->hdr.auth_len = RPC_AUTH_NTLMSSP_CHK_LEN;
- } else if (p->netsec_auth_validated) {
- p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN +
+ p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN +
data_len + ss_padding_len +
- RPC_HDR_AUTH_LEN + RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN;
- p->hdr.auth_len = RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN;
- } else {
- p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len;
- p->hdr.auth_len = 0;
- }
+ RPC_HDR_AUTH_LEN + NTLMSSP_SIG_SIZE;
+ p->hdr.auth_len = NTLMSSP_SIG_SIZE;
+
/*
* Init the parse struct to point at the outgoing
@@ -198,125 +161,281 @@ BOOL create_next_pdu(pipes_struct *p)
/* Store the header in the data stream. */
if(!smb_io_rpc_hdr("hdr", &p->hdr, &outgoing_pdu, 0)) {
- DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR.\n"));
+ DEBUG(0,("create_next_pdu_ntlmssp: failed to marshall RPC_HDR.\n"));
prs_mem_free(&outgoing_pdu);
return False;
}
if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) {
- DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_RESP.\n"));
+ DEBUG(0,("create_next_pdu_ntlmssp: failed to marshall RPC_HDR_RESP.\n"));
prs_mem_free(&outgoing_pdu);
return False;
}
- /* Store the current offset. */
- data_pos = prs_offset(&outgoing_pdu);
-
/* Copy the data into the PDU. */
if(!prs_append_some_prs_data(&outgoing_pdu, &p->out_data.rdata, p->out_data.data_sent_length, data_len)) {
- DEBUG(0,("create_next_pdu: failed to copy %u bytes of data.\n", (unsigned int)data_len));
+ DEBUG(0,("create_next_pdu_ntlmssp: failed to copy %u bytes of data.\n", (unsigned int)data_len));
prs_mem_free(&outgoing_pdu);
return False;
}
/* Copy the sign/seal padding data. */
if (ss_padding_len) {
- char pad[8];
+ unsigned char pad[8];
+
memset(pad, '\0', 8);
if (!prs_copy_data_in(&outgoing_pdu, pad, ss_padding_len)) {
- DEBUG(0,("create_next_pdu: failed to add %u bytes of pad data.\n", (unsigned int)ss_padding_len));
+ DEBUG(0,("create_next_pdu_ntlmssp: failed to add %u bytes of pad data.\n",
+ (unsigned int)ss_padding_len));
prs_mem_free(&outgoing_pdu);
return False;
}
}
- if (p->ntlmssp_auth_validated) {
- /*
- * NTLMSSP processing. Mutually exclusive with Schannel.
- */
- uint32 crc32 = 0;
- char *data;
-
- DEBUG(5,("create_next_pdu: sign: %s seal: %s data %d auth %d\n",
- BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len + ss_padding_len, p->hdr.auth_len));
-
- /*
- * Set data to point to where we copied the data into.
- */
- data = prs_data_p(&outgoing_pdu) + data_pos;
+ /* Now write out the auth header and null blob. */
+ if (p->auth.auth_type == PIPE_AUTH_TYPE_NTLMSSP) {
+ auth_type = RPC_NTLMSSP_AUTH_TYPE;
+ } else {
+ auth_type = RPC_SPNEGO_AUTH_TYPE;
+ }
+ if (p->auth.auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
+ auth_level = RPC_AUTH_LEVEL_PRIVACY;
+ } else {
+ auth_level = RPC_AUTH_LEVEL_INTEGRITY;
+ }
- if (auth_seal) {
- crc32 = crc32_calc_buffer(data, data_len + ss_padding_len);
- NTLMSSPcalc_p(p, (uchar*)data, data_len + ss_padding_len);
- }
+ init_rpc_hdr_auth(&auth_info, auth_type, auth_level, ss_padding_len, 1 /* context id. */);
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_ntlmssp: failed to marshall RPC_HDR_AUTH.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
- if (auth_seal || auth_verify) {
- RPC_HDR_AUTH auth_info;
+ /* Generate the sign blob. */
- init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE,
- auth_seal ? RPC_PIPE_AUTH_SEAL_LEVEL : RPC_PIPE_AUTH_SIGN_LEVEL,
- (auth_verify ? ss_padding_len : 0), (auth_verify ? 1 : 0));
- if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
- DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n"));
+ switch (p->auth.auth_level) {
+ case PIPE_AUTH_LEVEL_PRIVACY:
+ /* Data portion is encrypted. */
+ status = ntlmssp_seal_packet(a->ntlmssp_state,
+ prs_data_p(&outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
+ data_len + ss_padding_len,
+ prs_data_p(&outgoing_pdu),
+ (size_t)prs_offset(&outgoing_pdu),
+ &auth_blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ data_blob_free(&auth_blob);
prs_mem_free(&outgoing_pdu);
return False;
}
- }
-
- if (auth_verify) {
- RPC_AUTH_NTLMSSP_CHK ntlmssp_chk;
- char *auth_data = prs_data_p(&outgoing_pdu);
-
- p->ntlmssp_seq_num++;
- init_rpc_auth_ntlmssp_chk(&ntlmssp_chk, NTLMSSP_SIGN_VERSION,
- crc32, p->ntlmssp_seq_num++);
- auth_data = prs_data_p(&outgoing_pdu) + prs_offset(&outgoing_pdu) + 4;
- if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &ntlmssp_chk, &outgoing_pdu, 0)) {
- DEBUG(0,("create_next_pdu: failed to marshall RPC_AUTH_NTLMSSP_CHK.\n"));
+ break;
+ case PIPE_AUTH_LEVEL_INTEGRITY:
+ /* Data is signed. */
+ status = ntlmssp_sign_packet(a->ntlmssp_state,
+ prs_data_p(&outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
+ data_len + ss_padding_len,
+ prs_data_p(&outgoing_pdu),
+ (size_t)prs_offset(&outgoing_pdu),
+ &auth_blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ data_blob_free(&auth_blob);
prs_mem_free(&outgoing_pdu);
return False;
}
- NTLMSSPcalc_p(p, (uchar*)auth_data, RPC_AUTH_NTLMSSP_CHK_LEN - 4);
+ break;
+ default:
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /* Append the auth blob. */
+ if (!prs_copy_data_in(&outgoing_pdu, auth_blob.data, NTLMSSP_SIG_SIZE)) {
+ DEBUG(0,("create_next_pdu_ntlmssp: failed to add %u bytes auth blob.\n",
+ (unsigned int)NTLMSSP_SIG_SIZE));
+ data_blob_free(&auth_blob);
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ data_blob_free(&auth_blob);
+
+ /*
+ * Setup the counts for this PDU.
+ */
+
+ p->out_data.data_sent_length += data_len;
+ p->out_data.current_pdu_len = p->hdr.frag_len;
+ p->out_data.current_pdu_sent = 0;
+
+ prs_mem_free(&outgoing_pdu);
+ return True;
+}
+
+/*******************************************************************
+ Generate the next PDU to be returned from the data in p->rdata.
+ Return an schannel authenticated fragment.
+ ********************************************************************/
+
+static BOOL create_next_pdu_schannel(pipes_struct *p)
+{
+ RPC_HDR_RESP hdr_resp;
+ uint32 ss_padding_len = 0;
+ uint32 data_len;
+ uint32 data_space_available;
+ uint32 data_len_left;
+ prs_struct outgoing_pdu;
+ uint32 data_pos;
+
+ /*
+ * If we're in the fault state, keep returning fault PDU's until
+ * the pipe gets closed. JRA.
+ */
+
+ if(p->fault_state) {
+ setup_fault_pdu(p, NT_STATUS(0x1c010002));
+ return True;
+ }
+
+ memset((char *)&hdr_resp, '\0', sizeof(hdr_resp));
+
+ /* Change the incoming request header to a response. */
+ p->hdr.pkt_type = RPC_RESPONSE;
+
+ /* Set up rpc header flags. */
+ if (p->out_data.data_sent_length == 0) {
+ p->hdr.flags = RPC_FLG_FIRST;
+ } else {
+ p->hdr.flags = 0;
+ }
+
+ /*
+ * Work out how much we can fit in a single PDU.
+ */
+
+ data_len_left = prs_offset(&p->out_data.rdata) - p->out_data.data_sent_length;
+
+ /*
+ * Ensure there really is data left to send.
+ */
+
+ if(!data_len_left) {
+ DEBUG(0,("create_next_pdu_schannel: no data left to send !\n"));
+ return False;
+ }
+
+ data_space_available = sizeof(p->out_data.current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN -
+ RPC_HDR_AUTH_LEN - RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN;
+
+ /*
+ * The amount we send is the minimum of the available
+ * space and the amount left to send.
+ */
+
+ data_len = MIN(data_len_left, data_space_available);
+
+ /*
+ * Set up the alloc hint. This should be the data left to
+ * send.
+ */
+
+ hdr_resp.alloc_hint = data_len_left;
+
+ /*
+ * Work out if this PDU will be the last.
+ */
+
+ if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) {
+ p->hdr.flags |= RPC_FLG_LAST;
+ if (data_len_left % 8) {
+ ss_padding_len = 8 - (data_len_left % 8);
+ DEBUG(10,("create_next_pdu_schannel: adding sign/seal padding of %u\n",
+ ss_padding_len ));
+ }
+ }
+
+ p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len + ss_padding_len +
+ RPC_HDR_AUTH_LEN + RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN;
+ p->hdr.auth_len = RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN;
+
+ /*
+ * Init the parse struct to point at the outgoing
+ * data.
+ */
+
+ prs_init( &outgoing_pdu, 0, p->mem_ctx, MARSHALL);
+ prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /* Store the header in the data stream. */
+ if(!smb_io_rpc_hdr("hdr", &p->hdr, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_schannel: failed to marshall RPC_HDR.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_schannel: failed to marshall RPC_HDR_RESP.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /* Store the current offset. */
+ data_pos = prs_offset(&outgoing_pdu);
+
+ /* Copy the data into the PDU. */
+
+ if(!prs_append_some_prs_data(&outgoing_pdu, &p->out_data.rdata, p->out_data.data_sent_length, data_len)) {
+ DEBUG(0,("create_next_pdu_schannel: failed to copy %u bytes of data.\n", (unsigned int)data_len));
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
+
+ /* Copy the sign/seal padding data. */
+ if (ss_padding_len) {
+ char pad[8];
+ memset(pad, '\0', 8);
+ if (!prs_copy_data_in(&outgoing_pdu, pad, ss_padding_len)) {
+ DEBUG(0,("create_next_pdu_schannel: failed to add %u bytes of pad data.\n", (unsigned int)ss_padding_len));
+ prs_mem_free(&outgoing_pdu);
+ return False;
}
- } else if (p->netsec_auth_validated) {
+ }
+
+ {
/*
- * Schannel processing. Mutually exclusive with NTLMSSP.
+ * Schannel processing.
*/
- int auth_type, auth_level;
char *data;
RPC_HDR_AUTH auth_info;
-
- RPC_AUTH_NETSEC_CHK verf;
- prs_struct rverf;
- prs_struct rauth;
+ RPC_AUTH_SCHANNEL_CHK verf;
data = prs_data_p(&outgoing_pdu) + data_pos;
/* Check it's the type of reply we were expecting to decode */
- get_auth_type_level(p->netsec_auth.auth_flags, &auth_type, &auth_level);
- init_rpc_hdr_auth(&auth_info, auth_type, auth_level,
- ss_padding_len, 1);
+ init_rpc_hdr_auth(&auth_info,
+ RPC_SCHANNEL_AUTH_TYPE,
+ p->auth.auth_level == PIPE_AUTH_LEVEL_PRIVACY ?
+ RPC_AUTH_LEVEL_PRIVACY : RPC_AUTH_LEVEL_INTEGRITY,
+ ss_padding_len, 1);
if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
- DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n"));
+ DEBUG(0,("create_next_pdu_schannel: failed to marshall RPC_HDR_AUTH.\n"));
prs_mem_free(&outgoing_pdu);
return False;
}
- prs_init(&rverf, 0, p->mem_ctx, MARSHALL);
- prs_init(&rauth, 0, p->mem_ctx, MARSHALL);
-
- netsec_encode(&p->netsec_auth,
- p->netsec_auth.auth_flags,
+ schannel_encode(p->auth.a_u.schannel_auth,
+ p->auth.auth_level,
SENDER_IS_ACCEPTOR,
&verf, data, data_len + ss_padding_len);
- smb_io_rpc_auth_netsec_chk("", RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN,
- &verf, &outgoing_pdu, 0);
+ if (!smb_io_rpc_auth_schannel_chk("", RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN,
+ &verf, &outgoing_pdu, 0)) {
+ prs_mem_free(&outgoing_pdu);
+ return False;
+ }
- p->netsec_auth.seq_num++;
+ p->auth.a_u.schannel_auth->seq_num++;
}
/*
@@ -332,279 +451,299 @@ BOOL create_next_pdu(pipes_struct *p)
}
/*******************************************************************
- Process an NTLMSSP authentication response.
- If this function succeeds, the user has been authenticated
- and their domain, name and calling workstation stored in
- the pipe struct.
- The initial challenge is stored in p->challenge.
- *******************************************************************/
+ Generate the next PDU to be returned from the data in p->rdata.
+ No authentication done.
+********************************************************************/
-static BOOL api_pipe_ntlmssp_verify(pipes_struct *p, RPC_AUTH_NTLMSSP_RESP *ntlmssp_resp)
+static BOOL create_next_pdu_noauth(pipes_struct *p)
{
- uchar lm_owf[24];
- uchar nt_owf[128];
- int nt_pw_len;
- int lm_pw_len;
- fstring user_name;
- fstring domain;
- fstring wks;
+ RPC_HDR_RESP hdr_resp;
+ uint32 data_len;
+ uint32 data_space_available;
+ uint32 data_len_left;
+ prs_struct outgoing_pdu;
- NTSTATUS nt_status;
+ /*
+ * If we're in the fault state, keep returning fault PDU's until
+ * the pipe gets closed. JRA.
+ */
- struct auth_context *auth_context = NULL;
- auth_usersupplied_info *user_info = NULL;
- auth_serversupplied_info *server_info = NULL;
+ if(p->fault_state) {
+ setup_fault_pdu(p, NT_STATUS(0x1c010002));
+ return True;
+ }
- DEBUG(5,("api_pipe_ntlmssp_verify: checking user details\n"));
+ memset((char *)&hdr_resp, '\0', sizeof(hdr_resp));
- memset(p->user_name, '\0', sizeof(p->user_name));
- memset(p->pipe_user_name, '\0', sizeof(p->pipe_user_name));
- memset(p->domain, '\0', sizeof(p->domain));
- memset(p->wks, '\0', sizeof(p->wks));
+ /* Change the incoming request header to a response. */
+ p->hdr.pkt_type = RPC_RESPONSE;
- /* Set up for non-authenticated user. */
- delete_nt_token(&p->pipe_user.nt_user_token);
- p->pipe_user.ngroups = 0;
- SAFE_FREE( p->pipe_user.groups);
+ /* Set up rpc header flags. */
+ if (p->out_data.data_sent_length == 0) {
+ p->hdr.flags = RPC_FLG_FIRST;
+ } else {
+ p->hdr.flags = 0;
+ }
- /*
- * Setup an empty password for a guest user.
+ /*
+ * Work out how much we can fit in a single PDU.
*/
+ data_len_left = prs_offset(&p->out_data.rdata) - p->out_data.data_sent_length;
+
/*
- * We always negotiate UNICODE.
+ * Ensure there really is data left to send.
*/
- if (p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_UNICODE) {
- rpcstr_pull(user_name, ntlmssp_resp->user, sizeof(fstring), ntlmssp_resp->hdr_usr.str_str_len*2, 0 );
- rpcstr_pull(domain, ntlmssp_resp->domain, sizeof(fstring), ntlmssp_resp->hdr_domain.str_str_len*2, 0);
- rpcstr_pull(wks, ntlmssp_resp->wks, sizeof(fstring), ntlmssp_resp->hdr_wks.str_str_len*2, 0);
- } else {
- pull_ascii_fstring(user_name, ntlmssp_resp->user);
- pull_ascii_fstring(domain, ntlmssp_resp->domain);
- pull_ascii_fstring(wks, ntlmssp_resp->wks);
+ if(!data_len_left) {
+ DEBUG(0,("create_next_pdu_noath: no data left to send !\n"));
+ return False;
}
- DEBUG(5,("user: %s domain: %s wks: %s\n", user_name, domain, wks));
+ data_space_available = sizeof(p->out_data.current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;
- nt_pw_len = MIN(sizeof(nt_owf), ntlmssp_resp->hdr_nt_resp.str_str_len);
- lm_pw_len = MIN(sizeof(lm_owf), ntlmssp_resp->hdr_lm_resp.str_str_len);
+ /*
+ * The amount we send is the minimum of the available
+ * space and the amount left to send.
+ */
- memcpy(lm_owf, ntlmssp_resp->lm_resp, sizeof(lm_owf));
- memcpy(nt_owf, ntlmssp_resp->nt_resp, nt_pw_len);
+ data_len = MIN(data_len_left, data_space_available);
-#ifdef DEBUG_PASSWORD
- DEBUG(100,("lm, nt owfs, chal\n"));
- dump_data(100, (char *)lm_owf, sizeof(lm_owf));
- dump_data(100, (char *)nt_owf, nt_pw_len);
- dump_data(100, (char *)p->challenge, 8);
-#endif
+ /*
+ * Set up the alloc hint. This should be the data left to
+ * send.
+ */
+
+ hdr_resp.alloc_hint = data_len_left;
/*
- * Allow guest access. Patch from Shirish Kalele <kalele@veritas.com>.
+ * Work out if this PDU will be the last.
*/
- if (*user_name) {
+ if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) {
+ p->hdr.flags |= RPC_FLG_LAST;
+ }
- /*
- * Do the length checking only if user is not NULL.
- */
+ /*
+ * Set up the header lengths.
+ */
- if (ntlmssp_resp->hdr_lm_resp.str_str_len == 0)
- return False;
- if (ntlmssp_resp->hdr_nt_resp.str_str_len == 0)
- return False;
- if (ntlmssp_resp->hdr_usr.str_str_len == 0)
- return False;
- if (ntlmssp_resp->hdr_domain.str_str_len == 0)
- return False;
- if (ntlmssp_resp->hdr_wks.str_str_len == 0)
- return False;
+ p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len;
+ p->hdr.auth_len = 0;
+ /*
+ * Init the parse struct to point at the outgoing
+ * data.
+ */
+
+ prs_init( &outgoing_pdu, 0, p->mem_ctx, MARSHALL);
+ prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
+
+ /* Store the header in the data stream. */
+ if(!smb_io_rpc_hdr("hdr", &p->hdr, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_noath: failed to marshall RPC_HDR.\n"));
+ prs_mem_free(&outgoing_pdu);
+ return False;
}
-
- make_auth_context_fixed(&auth_context, (uchar*)p->challenge);
- if (!make_user_info_netlogon_network(&user_info,
- user_name, domain, wks,
- lm_owf, lm_pw_len,
- nt_owf, nt_pw_len)) {
- DEBUG(0,("make_user_info_netlogon_network failed! Failing authenticaion.\n"));
+ if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) {
+ DEBUG(0,("create_next_pdu_noath: failed to marshall RPC_HDR_RESP.\n"));
+ prs_mem_free(&outgoing_pdu);
return False;
}
-
- nt_status = auth_context->check_ntlm_password(auth_context, user_info, &server_info);
-
- (auth_context->free)(&auth_context);
- free_user_info(&user_info);
-
- p->ntlmssp_auth_validated = NT_STATUS_IS_OK(nt_status);
-
- if (!p->ntlmssp_auth_validated) {
- DEBUG(1,("api_pipe_ntlmssp_verify: User [%s]\\[%s] from machine %s \
-failed authentication on named pipe %s.\n", domain, user_name, wks, p->name ));
- free_server_info(&server_info);
+
+ /* Copy the data into the PDU. */
+
+ if(!prs_append_some_prs_data(&outgoing_pdu, &p->out_data.rdata, p->out_data.data_sent_length, data_len)) {
+ DEBUG(0,("create_next_pdu_noauth: failed to copy %u bytes of data.\n", (unsigned int)data_len));
+ prs_mem_free(&outgoing_pdu);
return False;
}
/*
- * Set up the sign/seal data.
+ * Setup the counts for this PDU.
*/
- if (server_info->lm_session_key.length != 16) {
- DEBUG(1,("api_pipe_ntlmssp_verify: User [%s]\\[%s] from machine %s \
-succeeded authentication on named pipe %s, but session key was of incorrect length [%u].\n",
- domain, user_name, wks, p->name, server_info->lm_session_key.length));
- free_server_info(&server_info);
- return False;
- } else {
- uchar p24[24];
- NTLMSSPOWFencrypt(server_info->lm_session_key.data, lm_owf, p24);
- {
- unsigned char j = 0;
- int ind;
+ p->out_data.data_sent_length += data_len;
+ p->out_data.current_pdu_len = p->hdr.frag_len;
+ p->out_data.current_pdu_sent = 0;
- unsigned char k2[8];
+ prs_mem_free(&outgoing_pdu);
+ return True;
+}
- memcpy(k2, p24, 5);
- k2[5] = 0xe5;
- k2[6] = 0x38;
- k2[7] = 0xb0;
+/*******************************************************************
+ Generate the next PDU to be returned from the data in p->rdata.
+********************************************************************/
- for (ind = 0; ind < 256; ind++)
- p->ntlmssp_hash[ind] = (unsigned char)ind;
+BOOL create_next_pdu(pipes_struct *p)
+{
+ switch(p->auth.auth_level) {
+ case PIPE_AUTH_LEVEL_NONE:
+ case PIPE_AUTH_LEVEL_CONNECT:
+ /* This is incorrect for auth level connect. Fixme. JRA */
+ return create_next_pdu_noauth(p);
+
+ default:
+ switch(p->auth.auth_type) {
+ case PIPE_AUTH_TYPE_NTLMSSP:
+ case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
+ return create_next_pdu_ntlmssp(p);
+ case PIPE_AUTH_TYPE_SCHANNEL:
+ return create_next_pdu_schannel(p);
+ default:
+ break;
+ }
+ }
- for( ind = 0; ind < 256; ind++) {
- unsigned char tc;
+ DEBUG(0,("create_next_pdu: invalid internal auth level %u / type %u",
+ (unsigned int)p->auth.auth_level,
+ (unsigned int)p->auth.auth_type));
+ return False;
+}
- j += (p->ntlmssp_hash[ind] + k2[ind%8]);
+/*******************************************************************
+ Process an NTLMSSP authentication response.
+ If this function succeeds, the user has been authenticated
+ and their domain, name and calling workstation stored in
+ the pipe struct.
+*******************************************************************/
- tc = p->ntlmssp_hash[ind];
- p->ntlmssp_hash[ind] = p->ntlmssp_hash[j];
- p->ntlmssp_hash[j] = tc;
- }
+static BOOL pipe_ntlmssp_verify_final(pipes_struct *p, DATA_BLOB *p_resp_blob)
+{
+ DATA_BLOB reply;
+ NTSTATUS status;
+ AUTH_NTLMSSP_STATE *a = p->auth.a_u.auth_ntlmssp_state;
- p->ntlmssp_hash[256] = 0;
- p->ntlmssp_hash[257] = 0;
- }
+ DEBUG(5,("pipe_ntlmssp_verify_final: checking user details\n"));
- dump_data_pw("NTLMSSP hash (v1)\n", p->ntlmssp_hash,
- sizeof(p->ntlmssp_hash));
+ ZERO_STRUCT(reply);
-/* NTLMSSPhash(p->ntlmssp_hash, p24); */
- p->ntlmssp_seq_num = 0;
+ memset(p->user_name, '\0', sizeof(p->user_name));
+ memset(p->pipe_user_name, '\0', sizeof(p->pipe_user_name));
+ memset(p->domain, '\0', sizeof(p->domain));
+ memset(p->wks, '\0', sizeof(p->wks));
+ /* Set up for non-authenticated user. */
+ delete_nt_token(&p->pipe_user.nt_user_token);
+ p->pipe_user.ngroups = 0;
+ SAFE_FREE( p->pipe_user.groups);
+
+ status = auth_ntlmssp_update(a, *p_resp_blob, &reply);
+
+ /* Don't generate a reply. */
+ data_blob_free(&reply);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
}
- fstrcpy(p->user_name, user_name);
- fstrcpy(p->pipe_user_name, server_info->unix_name);
- fstrcpy(p->domain, domain);
- fstrcpy(p->wks, wks);
+ fstrcpy(p->user_name, a->ntlmssp_state->user);
+ fstrcpy(p->pipe_user_name, a->server_info->unix_name);
+ fstrcpy(p->domain, a->ntlmssp_state->domain);
+ fstrcpy(p->wks, a->ntlmssp_state->workstation);
+
+ DEBUG(5,("pipe_ntlmssp_verify_final: OK: user: %s domain: %s workstation: %s\n",
+ p->user_name, p->domain, p->wks));
/*
* Store the UNIX credential data (uid/gid pair) in the pipe structure.
*/
- if (p->session_key.data) {
- data_blob_free(&p->session_key);
+ p->pipe_user.uid = a->server_info->uid;
+ p->pipe_user.gid = a->server_info->gid;
+
+ /*
+ * Copy the session key from the ntlmssp state.
+ */
+
+ data_blob_free(&p->session_key);
+ p->session_key = data_blob(a->ntlmssp_state->session_key.data, a->ntlmssp_state->session_key.length);
+ if (!p->session_key.data) {
+ return False;
}
- p->session_key = data_blob(server_info->lm_session_key.data, server_info->lm_session_key.length);
- p->pipe_user.uid = server_info->uid;
- p->pipe_user.gid = server_info->gid;
-
- p->pipe_user.ngroups = server_info->n_groups;
+ p->pipe_user.ngroups = a->server_info->n_groups;
if (p->pipe_user.ngroups) {
- if (!(p->pipe_user.groups = memdup(server_info->groups, sizeof(gid_t) * p->pipe_user.ngroups))) {
+ if (!(p->pipe_user.groups = memdup(a->server_info->groups, sizeof(gid_t) * p->pipe_user.ngroups))) {
DEBUG(0,("failed to memdup group list to p->pipe_user.groups\n"));
- free_server_info(&server_info);
return False;
}
}
- if (server_info->ptok)
- p->pipe_user.nt_user_token = dup_nt_token(server_info->ptok);
- else {
+ if (a->server_info->ptok) {
+ p->pipe_user.nt_user_token = dup_nt_token(a->server_info->ptok);
+ } else {
DEBUG(1,("Error: Authmodule failed to provide nt_user_token\n"));
p->pipe_user.nt_user_token = NULL;
- free_server_info(&server_info);
return False;
}
- p->ntlmssp_auth_validated = True;
-
- free_server_info(&server_info);
return True;
}
/*******************************************************************
The switch table for the pipe names and the functions to handle them.
- *******************************************************************/
+*******************************************************************/
-struct rpc_table
-{
- struct
- {
- const char *clnt;
- const char *srv;
- } pipe;
- struct api_struct *cmds;
- int n_cmds;
+struct rpc_table {
+ struct {
+ const char *clnt;
+ const char *srv;
+ } pipe;
+ struct api_struct *cmds;
+ int n_cmds;
};
static struct rpc_table *rpc_lookup;
static int rpc_lookup_size;
/*******************************************************************
- This is the client reply to our challenge for an authenticated
- bind request. The challenge we sent is in p->challenge.
+ This is the "stage3" NTLMSSP response after a bind request and reply.
*******************************************************************/
-BOOL api_pipe_bind_auth_resp(pipes_struct *p, prs_struct *rpc_in_p)
+BOOL api_pipe_bind_auth3(pipes_struct *p, prs_struct *rpc_in_p)
{
- RPC_HDR_AUTHA autha_info;
- RPC_AUTH_VERIFIER auth_verifier;
- RPC_AUTH_NTLMSSP_RESP ntlmssp_resp;
+ RPC_HDR_AUTH auth_info;
+ uint32 pad;
+ DATA_BLOB blob;
+
+ ZERO_STRUCT(blob);
- DEBUG(5,("api_pipe_bind_auth_resp: decode request. %d\n", __LINE__));
+ DEBUG(5,("api_pipe_bind_auth3: decode request. %d\n", __LINE__));
if (p->hdr.auth_len == 0) {
- DEBUG(0,("api_pipe_bind_auth_resp: No auth field sent !\n"));
- return False;
+ DEBUG(0,("api_pipe_bind_auth3: No auth field sent !\n"));
+ goto err;
+ }
+
+ /* 4 bytes padding. */
+ if (!prs_uint32("pad", rpc_in_p, 0, &pad)) {
+ DEBUG(0,("api_pipe_bind_auth3: unmarshall of 4 byte pad failed.\n"));
+ goto err;
}
/*
* Decode the authentication verifier response.
*/
- if(!smb_io_rpc_hdr_autha("", &autha_info, rpc_in_p, 0)) {
- DEBUG(0,("api_pipe_bind_auth_resp: unmarshall of RPC_HDR_AUTHA failed.\n"));
- return False;
+ if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_bind_auth3: unmarshall of RPC_HDR_AUTH failed.\n"));
+ goto err;
}
- if (autha_info.auth.auth_type != NTLMSSP_AUTH_TYPE || autha_info.auth.auth_level != RPC_PIPE_AUTH_SEAL_LEVEL) {
- DEBUG(0,("api_pipe_bind_auth_resp: incorrect auth type (%d) or level (%d).\n",
- (int)autha_info.auth.auth_type, (int)autha_info.auth.auth_level ));
+ if (auth_info.auth_type != RPC_NTLMSSP_AUTH_TYPE) {
+ DEBUG(0,("api_pipe_bind_auth3: incorrect auth type (%u).\n",
+ (unsigned int)auth_info.auth_type ));
return False;
}
- if(!smb_io_rpc_auth_verifier("", &auth_verifier, rpc_in_p, 0)) {
- DEBUG(0,("api_pipe_bind_auth_resp: unmarshall of RPC_AUTH_VERIFIER failed.\n"));
- return False;
- }
-
- /*
- * Ensure this is a NTLMSSP_AUTH packet type.
- */
-
- if (!rpc_auth_verifier_chk(&auth_verifier, "NTLMSSP", NTLMSSP_AUTH)) {
- DEBUG(0,("api_pipe_bind_auth_resp: rpc_auth_verifier_chk failed.\n"));
- return False;
- }
+ blob = data_blob(NULL,p->hdr.auth_len);
- if(!smb_io_rpc_auth_ntlmssp_resp("", &ntlmssp_resp, rpc_in_p, 0)) {
- DEBUG(0,("api_pipe_bind_auth_resp: Failed to unmarshall RPC_AUTH_NTLMSSP_RESP.\n"));
- return False;
+ if (!prs_copy_data_out(blob.data, rpc_in_p, p->hdr.auth_len)) {
+ DEBUG(0,("api_pipe_bind_auth3: Failed to pull %u bytes - the response blob.\n",
+ (unsigned int)p->hdr.auth_len ));
+ goto err;
}
/*
@@ -612,12 +751,23 @@ BOOL api_pipe_bind_auth_resp(pipes_struct *p, prs_struct *rpc_in_p)
* for correctness against the given DOMAIN\user name.
*/
- if (!api_pipe_ntlmssp_verify(p, &ntlmssp_resp))
- return False;
+ if (!pipe_ntlmssp_verify_final(p, &blob)) {
+ goto err;
+ }
+
+ data_blob_free(&blob);
+
+ p->pipe_bound = True;
- p->pipe_bound = True
-;
return True;
+
+ err:
+
+ data_blob_free(&blob);
+ free_pipe_ntlmssp_auth_data(&p->auth);
+ p->auth.a_u.auth_ntlmssp_state = NULL;
+
+ return False;
}
/*******************************************************************
@@ -642,13 +792,12 @@ static BOOL setup_bind_nak(pipes_struct *p)
prs_init( &outgoing_rpc, 0, p->mem_ctx, MARSHALL);
prs_give_memory( &outgoing_rpc, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
-
/*
* Initialize a bind_nak header.
*/
init_rpc_hdr(&nak_hdr, RPC_BINDNACK, RPC_FLG_FIRST | RPC_FLG_LAST,
- p->hdr.call_id, RPC_HEADER_LEN + sizeof(uint16), 0);
+ p->hdr.call_id, RPC_HEADER_LEN + sizeof(uint16), 0);
/*
* Marshall the header into the outgoing PDU.
@@ -673,6 +822,11 @@ static BOOL setup_bind_nak(pipes_struct *p)
p->out_data.current_pdu_len = prs_offset(&outgoing_rpc);
p->out_data.current_pdu_sent = 0;
+ if (p->auth.auth_data_free_func) {
+ (*p->auth.auth_data_free_func)(&p->auth);
+ }
+ p->auth.auth_level = PIPE_AUTH_LEVEL_NONE;
+ p->auth.auth_type = PIPE_AUTH_TYPE_NONE;
p->pipe_bound = False;
return True;
@@ -766,15 +920,13 @@ BOOL check_bind_req(struct pipes_struct *p, RPC_IFACE* abstract,
/* we have to check all now since win2k introduced a new UUID on the lsaprpc pipe */
- for ( i=0; pipe_names[i].client_pipe; i++ )
- {
+ for ( i=0; pipe_names[i].client_pipe; i++ ) {
DEBUG(10,("checking %s\n", pipe_names[i].client_pipe));
if ( strequal(pipe_names[i].client_pipe, pname)
&& (abstract->version == pipe_names[i].abstr_syntax.version)
&& (memcmp(&abstract->uuid, &pipe_names[i].abstr_syntax.uuid, sizeof(struct uuid)) == 0)
&& (transfer->version == pipe_names[i].trans_syntax.version)
- && (memcmp(&transfer->uuid, &pipe_names[i].trans_syntax.uuid, sizeof(struct uuid)) == 0) )
- {
+ && (memcmp(&transfer->uuid, &pipe_names[i].trans_syntax.uuid, sizeof(struct uuid)) == 0) ) {
struct api_struct *fns = NULL;
int n_fns = 0;
PIPE_RPC_FNS *context_fns;
@@ -800,8 +952,9 @@ BOOL check_bind_req(struct pipes_struct *p, RPC_IFACE* abstract,
}
}
- if(pipe_names[i].client_pipe == NULL)
+ if(pipe_names[i].client_pipe == NULL) {
return False;
+ }
return True;
}
@@ -809,6 +962,7 @@ BOOL check_bind_req(struct pipes_struct *p, RPC_IFACE* abstract,
/*******************************************************************
Register commands to an RPC pipe
*******************************************************************/
+
NTSTATUS rpc_pipe_register_commands(int version, const char *clnt, const char *srv, const struct api_struct *cmds, int size)
{
struct rpc_table *rpc_entry;
@@ -857,6 +1011,365 @@ NTSTATUS rpc_pipe_register_commands(int version, const char *clnt, const char *s
}
/*******************************************************************
+ Handle a SPNEGO krb5 bind auth.
+*******************************************************************/
+
+static BOOL pipe_spnego_auth_bind_kerberos(pipes_struct *p, prs_struct *rpc_in_p, RPC_HDR_AUTH *pauth_info,
+ DATA_BLOB *psecblob, prs_struct *pout_auth)
+{
+ return False;
+}
+
+/*******************************************************************
+ Handle the first part of a SPNEGO bind auth.
+*******************************************************************/
+
+static BOOL pipe_spnego_auth_bind_negotiate(pipes_struct *p, prs_struct *rpc_in_p,
+ RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
+{
+ DATA_BLOB blob;
+ DATA_BLOB secblob;
+ DATA_BLOB response;
+ DATA_BLOB chal;
+ char *OIDs[ASN1_MAX_OIDS];
+ int i;
+ NTSTATUS status;
+ BOOL got_kerberos_mechanism = False;
+ AUTH_NTLMSSP_STATE *a = NULL;
+ RPC_HDR_AUTH auth_info;
+
+ ZERO_STRUCT(secblob);
+ ZERO_STRUCT(chal);
+ ZERO_STRUCT(response);
+
+ /* Grab the SPNEGO blob. */
+ blob = data_blob(NULL,p->hdr.auth_len);
+
+ if (!prs_copy_data_out(blob.data, rpc_in_p, p->hdr.auth_len)) {
+ DEBUG(0,("pipe_spnego_auth_bind_negotiate: Failed to pull %u bytes - the SPNEGO auth header.\n",
+ (unsigned int)p->hdr.auth_len ));
+ goto err;
+ }
+
+ if (blob.data[0] != ASN1_APPLICATION(0)) {
+ goto err;
+ }
+
+ /* parse out the OIDs and the first sec blob */
+ if (!parse_negTokenTarg(blob, OIDs, &secblob)) {
+ DEBUG(0,("pipe_spnego_auth_bind_negotiate: Failed to parse the security blob.\n"));
+ goto err;
+ }
+
+ if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 || strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
+ got_kerberos_mechanism = True;
+ }
+
+ for (i=0;OIDs[i];i++) {
+ DEBUG(3,("pipe_spnego_auth_bind_negotiate: Got OID %s\n", OIDs[i]));
+ SAFE_FREE(OIDs[i]);
+ }
+ DEBUG(3,("pipe_spnego_auth_bind_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length));
+
+ if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
+ BOOL ret = pipe_spnego_auth_bind_kerberos(p, rpc_in_p, pauth_info, &secblob, pout_auth);
+ data_blob_free(&secblob);
+ data_blob_free(&blob);
+ return ret;
+ }
+
+ if (p->auth.auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP && p->auth.a_u.auth_ntlmssp_state) {
+ /* Free any previous auth type. */
+ free_pipe_ntlmssp_auth_data(&p->auth);
+ }
+
+ /* Initialize the NTLM engine. */
+ status = auth_ntlmssp_start(&a);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto err;
+ }
+
+ /*
+ * Pass the first security blob of data to it.
+ * This can return an error or NT_STATUS_MORE_PROCESSING_REQUIRED
+ * which means we need another packet to complete the bind.
+ */
+
+ status = auth_ntlmssp_update(a, secblob, &chal);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DEBUG(3,("pipe_spnego_auth_bind_negotiate: auth_ntlmssp_update failed.\n"));
+ goto err;
+ }
+
+ /* Generate the response blob we need for step 2 of the bind. */
+ response = spnego_gen_auth_response(&chal, status, OID_NTLMSSP);
+
+ /* Copy the blob into the pout_auth parse struct */
+ init_rpc_hdr_auth(&auth_info, RPC_SPNEGO_AUTH_TYPE, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
+ if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {
+ DEBUG(0,("pipe_spnego_auth_bind_negotiate: marshalling of RPC_HDR_AUTH failed.\n"));
+ goto err;
+ }
+
+ if (!prs_copy_data_in(pout_auth, response.data, response.length)) {
+ DEBUG(0,("pipe_spnego_auth_bind_negotiate: marshalling of data blob failed.\n"));
+ goto err;
+ }
+
+ p->auth.a_u.auth_ntlmssp_state = a;
+ p->auth.auth_data_free_func = &free_pipe_ntlmssp_auth_data;
+ p->auth.auth_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP;
+
+ data_blob_free(&blob);
+ data_blob_free(&secblob);
+ data_blob_free(&chal);
+ data_blob_free(&response);
+
+ /* We can't set pipe_bound True yet - we need an RPC_ALTER_CONTEXT response packet... */
+ return True;
+
+ err:
+
+ data_blob_free(&blob);
+ data_blob_free(&secblob);
+ data_blob_free(&chal);
+ data_blob_free(&response);
+
+ p->auth.a_u.auth_ntlmssp_state = NULL;
+
+ return False;
+}
+
+/*******************************************************************
+ Handle the second part of a SPNEGO bind auth.
+*******************************************************************/
+
+static BOOL pipe_spnego_auth_bind_continue(pipes_struct *p, prs_struct *rpc_in_p,
+ RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
+{
+ DATA_BLOB spnego_blob, auth_blob, auth_reply;
+ AUTH_NTLMSSP_STATE *a = p->auth.a_u.auth_ntlmssp_state;
+
+ ZERO_STRUCT(spnego_blob);
+ ZERO_STRUCT(auth_blob);
+ ZERO_STRUCT(auth_reply);
+
+ if (p->auth.auth_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP || !a) {
+ DEBUG(0,("pipe_spnego_auth_bind_continue: not in NTLMSSP auth state.\n"));
+ goto err;
+ }
+
+ /* Grab the SPNEGO blob. */
+ spnego_blob = data_blob(NULL,p->hdr.auth_len);
+
+ if (!prs_copy_data_out(spnego_blob.data, rpc_in_p, p->hdr.auth_len)) {
+ DEBUG(0,("pipe_spnego_auth_bind_continue: Failed to pull %u bytes - the SPNEGO auth header.\n",
+ (unsigned int)p->hdr.auth_len ));
+ goto err;
+ }
+
+ if (spnego_blob.data[0] != ASN1_CONTEXT(1)) {
+ DEBUG(0,("pipe_spnego_auth_bind_continue: invalid SPNEGO blob type.\n"));
+ goto err;
+ }
+
+ if (!spnego_parse_auth(spnego_blob, &auth_blob)) {
+ DEBUG(0,("pipe_spnego_auth_bind_continue: invalid SPNEGO blob.\n"));
+ goto err;
+ }
+
+ /*
+ * The following call actually checks the challenge/response data.
+ * for correctness against the given DOMAIN\user name.
+ */
+
+ if (!pipe_ntlmssp_verify_final(p, &auth_blob)) {
+ goto err;
+ }
+
+ data_blob_free(&spnego_blob);
+ data_blob_free(&auth_blob);
+ data_blob_free(&auth_reply);
+
+ p->pipe_bound = True;
+
+ return True;
+
+ err:
+
+ data_blob_free(&spnego_blob);
+ data_blob_free(&auth_blob);
+ data_blob_free(&auth_reply);
+
+ free_pipe_ntlmssp_auth_data(&p->auth);
+ p->auth.a_u.auth_ntlmssp_state = NULL;
+
+ return False;
+}
+
+/*******************************************************************
+ Handle an schannel bind auth.
+*******************************************************************/
+
+static BOOL pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
+ RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
+{
+ RPC_HDR_AUTH auth_info;
+ RPC_AUTH_SCHANNEL_NEG neg;
+ RPC_AUTH_VERIFIER auth_verifier;
+ uint32 flags;
+
+ if (!server_auth2_negotiated) {
+ DEBUG(0, ("pipe_schannel_auth_bind: Attempt to bind using schannel without successful serverauth2\n"));
+ return False;
+ }
+
+ if (!smb_io_rpc_auth_schannel_neg("", &neg, rpc_in_p, 0)) {
+ DEBUG(0,("pipe_schannel_auth_bind: Could not unmarshal SCHANNEL auth neg\n"));
+ return False;
+ }
+
+ p->auth.a_u.schannel_auth = TALLOC_P(p->pipe_state_mem_ctx, struct schannel_auth_struct);
+ if (!p->auth.a_u.schannel_auth) {
+ return False;
+ }
+
+ memset(p->auth.a_u.schannel_auth->sess_key, 0, sizeof(p->auth.a_u.schannel_auth->sess_key));
+ memcpy(p->auth.a_u.schannel_auth->sess_key, last_dcinfo.sess_key, sizeof(last_dcinfo.sess_key));
+
+ p->auth.a_u.schannel_auth->seq_num = 0;
+
+ /*
+ * JRA. Should we also copy the schannel session key into the pipe session key p->session_key
+ * here ? We do that for NTLMSPP, but the session key is already set up from the vuser
+ * struct of the person who opened the pipe. I need to test this further. JRA.
+ */
+
+ /* The client opens a second RPC NETLOGON pipe without
+ doing a auth2. The credentials for the schannel are
+ re-used from the auth2 the client did before. */
+ p->dc = TALLOC_ZERO_P(p->pipe_state_mem_ctx, struct dcinfo);
+ if (!p->dc) {
+ return False;
+ }
+ *p->dc = last_dcinfo;
+
+ init_rpc_hdr_auth(&auth_info, RPC_SCHANNEL_AUTH_TYPE, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
+ if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {
+ DEBUG(0,("pipe_schannel_auth_bind: marshalling of RPC_HDR_AUTH failed.\n"));
+ return False;
+ }
+
+ /*** SCHANNEL verifier ***/
+
+ init_rpc_auth_verifier(&auth_verifier, "\001", 0x0);
+ if(!smb_io_rpc_schannel_verifier("", &auth_verifier, pout_auth, 0)) {
+ DEBUG(0,("pipe_schannel_auth_bind: marshalling of RPC_AUTH_VERIFIER failed.\n"));
+ return False;
+ }
+
+ prs_align(pout_auth);
+
+ flags = 5;
+ if(!prs_uint32("flags ", pout_auth, 0, &flags)) {
+ return False;
+ }
+
+ DEBUG(10,("pipe_schannel_auth_bind: schannel auth: domain [%s] myname [%s]\n",
+ neg.domain, neg.myname));
+
+ /* We're finished with this bind - no more packets. */
+ p->auth.auth_data_free_func = NULL;
+ p->auth.auth_type = PIPE_AUTH_TYPE_SCHANNEL;
+
+ p->pipe_bound = True;
+
+ return True;
+}
+
+/*******************************************************************
+ Handle an NTLMSSP bind auth.
+*******************************************************************/
+
+static BOOL pipe_ntlmssp_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
+ RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
+{
+ RPC_HDR_AUTH auth_info;
+ DATA_BLOB blob;
+ DATA_BLOB response;
+ NTSTATUS status;
+ AUTH_NTLMSSP_STATE *a = NULL;
+
+ ZERO_STRUCT(blob);
+ ZERO_STRUCT(response);
+
+ /* Grab the NTLMSSP blob. */
+ blob = data_blob(NULL,p->hdr.auth_len);
+
+ if (!prs_copy_data_out(blob.data, rpc_in_p, p->hdr.auth_len)) {
+ DEBUG(0,("pipe_ntlmssp_auth_bind: Failed to pull %u bytes - the NTLM auth header.\n",
+ (unsigned int)p->hdr.auth_len ));
+ goto err;
+ }
+
+ if (strncmp(blob.data, "NTLMSSP", 7) != 0) {
+ DEBUG(0,("pipe_ntlmssp_auth_bind: Failed to read NTLMSSP in blob\n"));
+ goto err;
+ }
+
+ /* We have an NTLMSSP blob. */
+ status = auth_ntlmssp_start(&a);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("pipe_ntlmssp_auth_bind: auth_ntlmssp_start failed: %s\n",
+ nt_errstr(status) ));
+ goto err;
+ }
+
+ status = auth_ntlmssp_update(a, blob, &response);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DEBUG(0,("pipe_ntlmssp_auth_bind: auth_ntlmssp_update failed: %s\n",
+ nt_errstr(status) ));
+ goto err;
+ }
+
+ data_blob_free(&blob);
+
+ /* Copy the blob into the pout_auth parse struct */
+ init_rpc_hdr_auth(&auth_info, RPC_NTLMSSP_AUTH_TYPE, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
+ if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {
+ DEBUG(0,("pipe_ntlmssp_auth_bind: marshalling of RPC_HDR_AUTH failed.\n"));
+ goto err;
+ }
+
+ if (!prs_copy_data_in(pout_auth, response.data, response.length)) {
+ DEBUG(0,("pipe_ntlmssp_auth_bind: marshalling of data blob failed.\n"));
+ goto err;
+ }
+
+ p->auth.a_u.auth_ntlmssp_state = a;
+ p->auth.auth_data_free_func = &free_pipe_ntlmssp_auth_data;
+ p->auth.auth_type = PIPE_AUTH_TYPE_NTLMSSP;
+
+ data_blob_free(&blob);
+ data_blob_free(&response);
+
+ DEBUG(10,("pipe_ntlmssp_auth_bind: NTLMSSP auth started\n"));
+
+ /* We can't set pipe_bound True yet - we need an RPC_AUTH3 response packet... */
+ return True;
+
+ err:
+
+ data_blob_free(&blob);
+ data_blob_free(&response);
+
+ free_pipe_ntlmssp_auth_data(&p->auth);
+ p->auth.a_u.auth_ntlmssp_state = NULL;
+ return False;
+}
+
+/*******************************************************************
Respond to a pipe bind request.
*******************************************************************/
@@ -872,10 +1385,41 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
prs_struct outgoing_rpc;
int i = 0;
int auth_len = 0;
- enum RPC_PKT_TYPE reply_pkt_type;
+ unsigned int auth_type = RPC_ANONYMOUS_AUTH_TYPE;
+
+ /* No rebinds on a bound pipe - use alter context. */
+ if (p->pipe_bound) {
+ DEBUG(2,("api_pipe_bind_req: rejecting bind request on bound pipe %s.\n", p->pipe_srv_name));
+ return setup_bind_nak(p);
+ }
+
+ prs_init( &outgoing_rpc, 0, p->mem_ctx, MARSHALL);
+
+ /*
+ * Marshall directly into the outgoing PDU space. We
+ * must do this as we need to set to the bind response
+ * header and are never sending more than one PDU here.
+ */
+
+ prs_give_memory( &outgoing_rpc, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
- p->ntlmssp_auth_requested = False;
- p->netsec_auth_validated = False;
+ /*
+ * Setup the memory to marshall the ba header, and the
+ * auth footers.
+ */
+
+ if(!prs_init(&out_hdr_ba, 1024, p->mem_ctx, MARSHALL)) {
+ DEBUG(0,("api_pipe_bind_req: malloc out_hdr_ba failed.\n"));
+ prs_mem_free(&outgoing_rpc);
+ return False;
+ }
+
+ if(!prs_init(&out_auth, 1024, p->mem_ctx, MARSHALL)) {
+ DEBUG(0,("api_pipe_bind_req: malloc out_auth failed.\n"));
+ prs_mem_free(&outgoing_rpc);
+ prs_mem_free(&out_hdr_ba);
+ return False;
+ }
DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__));
@@ -887,17 +1431,21 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
for (i = 0; i < rpc_lookup_size; i++) {
if (strequal(rpc_lookup[i].pipe.clnt, p->name)) {
- DEBUG(3, ("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n",
- rpc_lookup[i].pipe.clnt, rpc_lookup[i].pipe.srv));
- fstrcpy(p->pipe_srv_name, rpc_lookup[i].pipe.srv);
- break;
- }
+ DEBUG(3, ("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n",
+ rpc_lookup[i].pipe.clnt, rpc_lookup[i].pipe.srv));
+ fstrcpy(p->pipe_srv_name, rpc_lookup[i].pipe.srv);
+ break;
+ }
}
if (i == rpc_lookup_size) {
if (NT_STATUS_IS_ERR(smb_probe_module("rpc", p->name))) {
- DEBUG(3,("api_pipe_bind_req: Unknown pipe name %s in bind request.\n",
- p->name ));
+ DEBUG(3,("api_pipe_bind_req: Unknown pipe name %s in bind request.\n",
+ p->name ));
+ prs_mem_free(&outgoing_rpc);
+ prs_mem_free(&out_hdr_ba);
+ prs_mem_free(&out_auth);
+
return setup_bind_nak(p);
}
@@ -912,122 +1460,205 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
if (i == rpc_lookup_size) {
DEBUG(0, ("module %s doesn't provide functions for pipe %s!\n", p->name, p->name));
- return False;
+ goto err_exit;
}
}
/* decode the bind request */
if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_in_p, 0)) {
DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_RB struct.\n"));
- return setup_bind_nak(p);
+ goto err_exit;
}
+ /* name has to be \PIPE\xxxxx */
+ fstrcpy(ack_pipe_name, "\\PIPE\\");
+ fstrcat(ack_pipe_name, p->pipe_srv_name);
+
+ DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__));
+
/*
- * Check if this is an authenticated request.
+ * Check if this is an authenticated bind request.
*/
- if (p->hdr.auth_len != 0) {
- RPC_AUTH_VERIFIER auth_verifier;
- RPC_AUTH_NTLMSSP_NEG ntlmssp_neg;
-
+ if (p->hdr.auth_len) {
/*
* Decode the authentication verifier.
*/
if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) {
DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_AUTH struct.\n"));
- return setup_bind_nak(p);
+ goto err_exit;
}
- switch(auth_info.auth_type) {
- case NTLMSSP_AUTH_TYPE:
+ auth_type = auth_info.auth_type;
- if(!smb_io_rpc_auth_verifier("", &auth_verifier, rpc_in_p, 0)) {
- DEBUG(0,("api_pipe_bind_req: unable to "
- "unmarshall RPC_HDR_AUTH struct.\n"));
- return setup_bind_nak(p);
- }
+ /* Work out if we have to sign or seal etc. */
+ switch (auth_info.auth_level) {
+ case RPC_AUTH_LEVEL_INTEGRITY:
+ p->auth.auth_level = PIPE_AUTH_LEVEL_INTEGRITY;
+ break;
+ case RPC_AUTH_LEVEL_PRIVACY:
+ p->auth.auth_level = PIPE_AUTH_LEVEL_PRIVACY;
+ break;
+ default:
+ DEBUG(0,("api_pipe_bind_req: unexpected auth level (%u).\n",
+ (unsigned int)auth_info.auth_level ));
+ goto err_exit;
+ }
+ } else {
+ ZERO_STRUCT(auth_info);
+ }
- if(!strequal(auth_verifier.signature, "NTLMSSP")) {
- DEBUG(0,("api_pipe_bind_req: "
- "auth_verifier.signature != NTLMSSP\n"));
- return setup_bind_nak(p);
- }
+ assoc_gid = hdr_rb.bba.assoc_gid ? hdr_rb.bba.assoc_gid : 0x53f0;
- if(auth_verifier.msg_type != NTLMSSP_NEGOTIATE) {
- DEBUG(0,("api_pipe_bind_req: "
- "auth_verifier.msg_type (%d) != NTLMSSP_NEGOTIATE\n",
- auth_verifier.msg_type));
- return setup_bind_nak(p);
- }
+ switch(auth_type) {
+ case RPC_NTLMSSP_AUTH_TYPE:
+ if (!pipe_ntlmssp_auth_bind(p, rpc_in_p, &auth_info, &out_auth)) {
+ goto err_exit;
+ }
+ assoc_gid = 0x7a77;
+ break;
- if(!smb_io_rpc_auth_ntlmssp_neg("", &ntlmssp_neg, rpc_in_p, 0)) {
- DEBUG(0,("api_pipe_bind_req: "
- "Failed to unmarshall RPC_AUTH_NTLMSSP_NEG.\n"));
- return setup_bind_nak(p);
- }
+ case RPC_SCHANNEL_AUTH_TYPE:
+ if (!pipe_schannel_auth_bind(p, rpc_in_p, &auth_info, &out_auth)) {
+ goto err_exit;
+ }
+ break;
- p->ntlmssp_chal_flags = SMBD_NTLMSSP_NEG_FLAGS;
- p->ntlmssp_auth_requested = True;
- break;
+ case RPC_SPNEGO_AUTH_TYPE:
+ if (!pipe_spnego_auth_bind_negotiate(p, rpc_in_p, &auth_info, &out_auth)) {
+ goto err_exit;
+ }
+ break;
- case NETSEC_AUTH_TYPE:
- {
- RPC_AUTH_NETSEC_NEG neg;
- struct netsec_auth_struct *a = &(p->netsec_auth);
+ case RPC_ANONYMOUS_AUTH_TYPE:
+ /* Unauthenticated bind request. */
+ /* We're finished - no more packets. */
+ p->auth.auth_type = PIPE_AUTH_TYPE_NONE;
+ /* We must set the pipe auth_level here also. */
+ p->auth.auth_level = PIPE_AUTH_LEVEL_NONE;
+ p->pipe_bound = True;
+ break;
- if (!server_auth2_negotiated) {
- DEBUG(0, ("Attempt to bind using schannel "
- "without successful serverauth2\n"));
- return setup_bind_nak(p);
- }
+ default:
+ DEBUG(0,("api_pipe_bind_req: unknown auth type %x requested.\n", auth_type ));
+ goto err_exit;
+ }
- if (!smb_io_rpc_auth_netsec_neg("", &neg, rpc_in_p, 0)) {
- DEBUG(0,("api_pipe_bind_req: "
- "Could not unmarshal SCHANNEL auth neg\n"));
- return setup_bind_nak(p);
- }
+ /*
+ * Create the bind response struct.
+ */
- p->netsec_auth_validated = True;
+ /* If the requested abstract synt uuid doesn't match our client pipe,
+ reject the bind_ack & set the transfer interface synt to all 0's,
+ ver 0 (observed when NT5 attempts to bind to abstract interfaces
+ unknown to NT4)
+ Needed when adding entries to a DACL from NT5 - SK */
- memset(a->sess_key, 0, sizeof(a->sess_key));
- memcpy(a->sess_key, last_dcinfo.sess_key, sizeof(last_dcinfo.sess_key));
+ if(check_bind_req(p, &hdr_rb.rpc_context[0].abstract, &hdr_rb.rpc_context[0].transfer[0],
+ hdr_rb.rpc_context[0].context_id )) {
+ init_rpc_hdr_ba(&hdr_ba,
+ RPC_MAX_PDU_FRAG_LEN,
+ RPC_MAX_PDU_FRAG_LEN,
+ assoc_gid,
+ ack_pipe_name,
+ 0x1, 0x0, 0x0,
+ &hdr_rb.rpc_context[0].transfer[0]);
+ } else {
+ RPC_IFACE null_interface;
+ ZERO_STRUCT(null_interface);
+ /* Rejection reason: abstract syntax not supported */
+ init_rpc_hdr_ba(&hdr_ba, RPC_MAX_PDU_FRAG_LEN,
+ RPC_MAX_PDU_FRAG_LEN, assoc_gid,
+ ack_pipe_name, 0x1, 0x2, 0x1,
+ &null_interface);
+ p->pipe_bound = False;
+ }
- a->seq_num = 0;
+ /*
+ * and marshall it.
+ */
- DEBUG(10,("schannel auth: domain [%s] myname [%s]\n",
- neg.domain, neg.myname));
- break;
- }
+ if(!smb_io_rpc_hdr_ba("", &hdr_ba, &out_hdr_ba, 0)) {
+ DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_BA failed.\n"));
+ goto err_exit;
+ }
- case SPNEGO_AUTH_TYPE:
- default:
- DEBUG(0,("api_pipe_bind_req: unknown auth type %x requested.\n",
- auth_info.auth_type ));
- return setup_bind_nak(p);
- }
+ /*
+ * Create the header, now we know the length.
+ */
+
+ if (prs_offset(&out_auth)) {
+ auth_len = prs_offset(&out_auth) - RPC_HDR_AUTH_LEN;
}
- switch(p->hdr.pkt_type) {
- case RPC_BIND:
- /* name has to be \PIPE\xxxxx */
- fstrcpy(ack_pipe_name, "\\PIPE\\");
- fstrcat(ack_pipe_name, p->pipe_srv_name);
- reply_pkt_type = RPC_BINDACK;
- break;
- case RPC_ALTCONT:
- /* secondary address CAN be NULL
- * as the specs say it's ignored.
- * It MUST NULL to have the spoolss working.
- */
- fstrcpy(ack_pipe_name,"");
- reply_pkt_type = RPC_ALTCONTRESP;
- break;
- default:
- return False;
+ init_rpc_hdr(&p->hdr, RPC_BINDACK, RPC_FLG_FIRST | RPC_FLG_LAST,
+ p->hdr.call_id,
+ RPC_HEADER_LEN + prs_offset(&out_hdr_ba) + prs_offset(&out_auth),
+ auth_len);
+
+ /*
+ * Marshall the header into the outgoing PDU.
+ */
+
+ if(!smb_io_rpc_hdr("", &p->hdr, &outgoing_rpc, 0)) {
+ DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR failed.\n"));
+ goto err_exit;
}
- DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__));
+ /*
+ * Now add the RPC_HDR_BA and any auth needed.
+ */
+
+ if(!prs_append_prs_data( &outgoing_rpc, &out_hdr_ba)) {
+ DEBUG(0,("api_pipe_bind_req: append of RPC_HDR_BA failed.\n"));
+ goto err_exit;
+ }
+
+ if (auth_len && !prs_append_prs_data( &outgoing_rpc, &out_auth)) {
+ DEBUG(0,("api_pipe_bind_req: append of auth info failed.\n"));
+ goto err_exit;
+ }
+
+ /*
+ * Setup the lengths for the initial reply.
+ */
+
+ p->out_data.data_sent_length = 0;
+ p->out_data.current_pdu_len = prs_offset(&outgoing_rpc);
+ p->out_data.current_pdu_sent = 0;
+
+ prs_mem_free(&out_hdr_ba);
+ prs_mem_free(&out_auth);
+
+ return True;
+
+ err_exit:
+
+ prs_mem_free(&outgoing_rpc);
+ prs_mem_free(&out_hdr_ba);
+ prs_mem_free(&out_auth);
+ return setup_bind_nak(p);
+}
+
+/****************************************************************************
+ Deal with an alter context call. Can be third part of 3 leg auth request for
+ SPNEGO calls.
+****************************************************************************/
+
+BOOL api_pipe_alter_context(pipes_struct *p, prs_struct *rpc_in_p)
+{
+ RPC_HDR_BA hdr_ba;
+ RPC_HDR_RB hdr_rb;
+ RPC_HDR_AUTH auth_info;
+ uint16 assoc_gid;
+ fstring ack_pipe_name;
+ prs_struct out_hdr_ba;
+ prs_struct out_auth;
+ prs_struct outgoing_rpc;
+ int auth_len = 0;
+
+ prs_init( &outgoing_rpc, 0, p->mem_ctx, MARSHALL);
/*
* Marshall directly into the outgoing PDU space. We
@@ -1035,7 +1666,6 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
* header and are never sending more than one PDU here.
*/
- prs_init( &outgoing_rpc, 0, p->mem_ctx, MARSHALL);
prs_give_memory( &outgoing_rpc, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False);
/*
@@ -1044,22 +1674,68 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
*/
if(!prs_init(&out_hdr_ba, 1024, p->mem_ctx, MARSHALL)) {
- DEBUG(0,("api_pipe_bind_req: malloc out_hdr_ba failed.\n"));
+ DEBUG(0,("api_pipe_alter_context: malloc out_hdr_ba failed.\n"));
prs_mem_free(&outgoing_rpc);
return False;
}
if(!prs_init(&out_auth, 1024, p->mem_ctx, MARSHALL)) {
- DEBUG(0,("pi_pipe_bind_req: malloc out_auth failed.\n"));
+ DEBUG(0,("api_pipe_alter_context: malloc out_auth failed.\n"));
prs_mem_free(&outgoing_rpc);
prs_mem_free(&out_hdr_ba);
return False;
}
- if (p->ntlmssp_auth_requested)
- assoc_gid = 0x7a77;
- else
- assoc_gid = hdr_rb.bba.assoc_gid ? hdr_rb.bba.assoc_gid : 0x53f0;
+ DEBUG(5,("api_pipe_alter_context: decode request. %d\n", __LINE__));
+
+ /* decode the alter context request */
+ if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_alter_context: unable to unmarshall RPC_HDR_RB struct.\n"));
+ goto err_exit;
+ }
+
+ /* secondary address CAN be NULL
+ * as the specs say it's ignored.
+ * It MUST be NULL to have the spoolss working.
+ */
+ fstrcpy(ack_pipe_name,"");
+
+ DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__));
+
+ /*
+ * Check if this is an authenticated alter context request.
+ */
+
+ if (p->hdr.auth_len != 0) {
+ /*
+ * Decode the authentication verifier.
+ */
+
+ if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) {
+ DEBUG(0,("api_pipe_alter_context: unable to unmarshall RPC_HDR_AUTH struct.\n"));
+ goto err_exit;
+ }
+
+ /*
+ * Currently only the SPNEGO auth type uses the alter ctx
+ * response in place of the NTLMSSP auth3 type.
+ */
+
+ if (auth_info.auth_type == RPC_SPNEGO_AUTH_TYPE) {
+ /* We can only finish if the pipe is unbound. */
+ if (!p->pipe_bound) {
+ if (!pipe_spnego_auth_bind_continue(p, rpc_in_p, &auth_info, &out_auth)) {
+ goto err_exit;
+ }
+ } else {
+ goto err_exit;
+ }
+ }
+ } else {
+ ZERO_STRUCT(auth_info);
+ }
+
+ assoc_gid = hdr_rb.bba.assoc_gid ? hdr_rb.bba.assoc_gid : 0x53f0;
/*
* Create the bind response struct.
@@ -1074,8 +1750,8 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
if(check_bind_req(p, &hdr_rb.rpc_context[0].abstract, &hdr_rb.rpc_context[0].transfer[0],
hdr_rb.rpc_context[0].context_id )) {
init_rpc_hdr_ba(&hdr_ba,
- MAX_PDU_FRAG_LEN,
- MAX_PDU_FRAG_LEN,
+ RPC_MAX_PDU_FRAG_LEN,
+ RPC_MAX_PDU_FRAG_LEN,
assoc_gid,
ack_pipe_name,
0x1, 0x0, 0x0,
@@ -1084,10 +1760,11 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
RPC_IFACE null_interface;
ZERO_STRUCT(null_interface);
/* Rejection reason: abstract syntax not supported */
- init_rpc_hdr_ba(&hdr_ba, MAX_PDU_FRAG_LEN,
- MAX_PDU_FRAG_LEN, assoc_gid,
+ init_rpc_hdr_ba(&hdr_ba, RPC_MAX_PDU_FRAG_LEN,
+ RPC_MAX_PDU_FRAG_LEN, assoc_gid,
ack_pipe_name, 0x1, 0x2, 0x1,
&null_interface);
+ p->pipe_bound = False;
}
/*
@@ -1095,85 +1772,19 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
*/
if(!smb_io_rpc_hdr_ba("", &hdr_ba, &out_hdr_ba, 0)) {
- DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_BA failed.\n"));
+ DEBUG(0,("api_pipe_alter_context: marshalling of RPC_HDR_BA failed.\n"));
goto err_exit;
}
/*
- * Now the authentication.
+ * Create the header, now we know the length.
*/
- if (p->ntlmssp_auth_requested) {
- RPC_AUTH_VERIFIER auth_verifier;
- RPC_AUTH_NTLMSSP_CHAL ntlmssp_chal;
-
- generate_random_buffer(p->challenge, 8);
-
- /*** Authentication info ***/
-
- init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, RPC_PIPE_AUTH_SEAL_LEVEL, RPC_HDR_AUTH_LEN, 1);
- if(!smb_io_rpc_hdr_auth("", &auth_info, &out_auth, 0)) {
- DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_AUTH failed.\n"));
- goto err_exit;
- }
-
- /*** NTLMSSP verifier ***/
-
- init_rpc_auth_verifier(&auth_verifier, "NTLMSSP", NTLMSSP_CHALLENGE);
- if(!smb_io_rpc_auth_verifier("", &auth_verifier, &out_auth, 0)) {
- DEBUG(0,("api_pipe_bind_req: marshalling of RPC_AUTH_VERIFIER failed.\n"));
- goto err_exit;
- }
-
- /* NTLMSSP challenge ***/
-
- init_rpc_auth_ntlmssp_chal(&ntlmssp_chal, p->ntlmssp_chal_flags, p->challenge);
- if(!smb_io_rpc_auth_ntlmssp_chal("", &ntlmssp_chal, &out_auth, 0)) {
- DEBUG(0,("api_pipe_bind_req: marshalling of RPC_AUTH_NTLMSSP_CHAL failed.\n"));
- goto err_exit;
- }
-
- /* Auth len in the rpc header doesn't include auth_header. */
- auth_len = prs_offset(&out_auth) - RPC_HDR_AUTH_LEN;
- }
-
- if (p->netsec_auth_validated) {
- RPC_AUTH_VERIFIER auth_verifier;
- uint32 flags;
-
- /* The client opens a second RPC NETLOGON pipe without
- doing a auth2. The credentials for the schannel are
- re-used from the auth2 the client did before. */
- p->dc = last_dcinfo;
-
- init_rpc_hdr_auth(&auth_info, NETSEC_AUTH_TYPE, auth_info.auth_level, RPC_HDR_AUTH_LEN, 1);
- if(!smb_io_rpc_hdr_auth("", &auth_info, &out_auth, 0)) {
- DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_AUTH failed.\n"));
- goto err_exit;
- }
-
- /*** NETSEC verifier ***/
-
- init_rpc_auth_verifier(&auth_verifier, "\001", 0x0);
- if(!smb_io_rpc_netsec_verifier("", &auth_verifier, &out_auth, 0)) {
- DEBUG(0,("api_pipe_bind_req: marshalling of RPC_AUTH_VERIFIER failed.\n"));
- goto err_exit;
- }
-
- prs_align(&out_auth);
-
- flags = 5;
- if(!prs_uint32("flags ", &out_auth, 0, &flags))
- goto err_exit;
-
+ if (prs_offset(&out_auth)) {
auth_len = prs_offset(&out_auth) - RPC_HDR_AUTH_LEN;
}
- /*
- * Create the header, now we know the length.
- */
-
- init_rpc_hdr(&p->hdr, reply_pkt_type, RPC_FLG_FIRST | RPC_FLG_LAST,
+ init_rpc_hdr(&p->hdr, RPC_ALTCONTRESP, RPC_FLG_FIRST | RPC_FLG_LAST,
p->hdr.call_id,
RPC_HEADER_LEN + prs_offset(&out_hdr_ba) + prs_offset(&out_auth),
auth_len);
@@ -1183,7 +1794,7 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
*/
if(!smb_io_rpc_hdr("", &p->hdr, &outgoing_rpc, 0)) {
- DEBUG(0,("pi_pipe_bind_req: marshalling of RPC_HDR failed.\n"));
+ DEBUG(0,("api_pipe_alter_context: marshalling of RPC_HDR failed.\n"));
goto err_exit;
}
@@ -1192,19 +1803,15 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
*/
if(!prs_append_prs_data( &outgoing_rpc, &out_hdr_ba)) {
- DEBUG(0,("api_pipe_bind_req: append of RPC_HDR_BA failed.\n"));
+ DEBUG(0,("api_pipe_alter_context: append of RPC_HDR_BA failed.\n"));
goto err_exit;
}
- if((p->ntlmssp_auth_requested|p->netsec_auth_validated) &&
- !prs_append_prs_data( &outgoing_rpc, &out_auth)) {
- DEBUG(0,("api_pipe_bind_req: append of auth info failed.\n"));
+ if (auth_len && !prs_append_prs_data( &outgoing_rpc, &out_auth)) {
+ DEBUG(0,("api_pipe_alter_context: append of auth info failed.\n"));
goto err_exit;
}
- if(!p->ntlmssp_auth_requested)
- p->pipe_bound = True;
-
/*
* Setup the lengths for the initial reply.
*/
@@ -1223,138 +1830,141 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
prs_mem_free(&outgoing_rpc);
prs_mem_free(&out_hdr_ba);
prs_mem_free(&out_auth);
- return False;
+ return setup_bind_nak(p);
}
/****************************************************************************
- Deal with sign & seal processing on an RPC request.
+ Deal with NTLMSSP sign & seal processing on an RPC request.
****************************************************************************/
-BOOL api_pipe_auth_process(pipes_struct *p, prs_struct *rpc_in)
+BOOL api_pipe_ntlmssp_auth_process(pipes_struct *p, prs_struct *rpc_in,
+ uint32 *p_ss_padding_len, NTSTATUS *pstatus)
{
- /*
- * We always negotiate the following two bits....
- */
- BOOL auth_verify = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) != 0);
- BOOL auth_seal = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SEAL) != 0);
- int data_len;
- int auth_len;
- uint32 old_offset;
- uint32 crc32 = 0;
+ RPC_HDR_AUTH auth_info;
+ uint32 auth_len = p->hdr.auth_len;
+ uint32 save_offset = prs_offset(rpc_in);
+ AUTH_NTLMSSP_STATE *a = p->auth.a_u.auth_ntlmssp_state;
+ unsigned char *data = NULL;
+ size_t data_len;
+ unsigned char *full_packet_data = NULL;
+ size_t full_packet_data_len;
+ DATA_BLOB auth_blob;
+
+ *pstatus = NT_STATUS_OK;
- auth_len = p->hdr.auth_len;
+ if (p->auth.auth_level == PIPE_AUTH_LEVEL_NONE || p->auth.auth_level == PIPE_AUTH_LEVEL_CONNECT) {
+ return True;
+ }
+
+ if (!a) {
+ *pstatus = NT_STATUS_INVALID_PARAMETER;
+ return False;
+ }
- if ((auth_len != RPC_AUTH_NTLMSSP_CHK_LEN) && auth_verify) {
- DEBUG(0,("api_pipe_auth_process: Incorrect auth_len %d.\n", auth_len ));
+ /* Ensure there's enough data for an authenticated request. */
+ if ((auth_len > RPC_MAX_SIGN_SIZE) ||
+ (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + RPC_HDR_AUTH_LEN + auth_len > p->hdr.frag_len)) {
+ DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len %u is too large.\n",
+ (unsigned int)auth_len ));
+ *pstatus = NT_STATUS_INVALID_PARAMETER;
return False;
}
/*
- * The following is that length of the data we must verify or unseal.
- * This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN
- * preceeding the auth_data.
+ * We need the full packet data + length (minus auth stuff) as well as the packet data + length
+ * after the RPC header.
+ * We need to pass in the full packet (minus auth len) to the NTLMSSP sign and check seal
+ * functions as NTLMv2 checks the rpc headers also.
*/
- data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
- (auth_verify ? RPC_HDR_AUTH_LEN : 0) - auth_len;
-
- DEBUG(5,("api_pipe_auth_process: sign: %s seal: %s data %d auth %d\n",
- BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len, auth_len));
+ data = (unsigned char *)(prs_data_p(rpc_in) + RPC_HDR_REQ_LEN);
+ data_len = (size_t)(p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - RPC_HDR_AUTH_LEN - auth_len);
- if (auth_seal) {
- /*
- * The data in rpc_in doesn't contain the RPC_HEADER as this
- * has already been consumed.
- */
- char *data = prs_data_p(rpc_in) + RPC_HDR_REQ_LEN;
- dump_data_pw("NTLMSSP hash (v1)\n", p->ntlmssp_hash,
- sizeof(p->ntlmssp_hash));
+ full_packet_data = p->in_data.current_in_pdu;
+ full_packet_data_len = p->hdr.frag_len - auth_len;
- dump_data_pw("Incoming RPC PDU (NTLMSSP sealed)\n",
- (const unsigned char *)data, data_len);
- NTLMSSPcalc_p(p, (uchar*)data, data_len);
- dump_data_pw("Incoming RPC PDU (NTLMSSP unsealed)\n",
- (const unsigned char *)data, data_len);
- crc32 = crc32_calc_buffer(data, data_len);
+ /* Pull the auth header and the following data into a blob. */
+ if(!prs_set_offset(rpc_in, RPC_HDR_REQ_LEN + data_len)) {
+ DEBUG(0,("api_pipe_ntlmssp_auth_process: cannot move offset to %u.\n",
+ (unsigned int)RPC_HDR_REQ_LEN + (unsigned int)data_len ));
+ *pstatus = NT_STATUS_INVALID_PARAMETER;
+ return False;
}
- old_offset = prs_offset(rpc_in);
-
- if (auth_seal || auth_verify) {
- RPC_HDR_AUTH auth_info;
-
- if(!prs_set_offset(rpc_in, old_offset + data_len)) {
- DEBUG(0,("api_pipe_auth_process: cannot move offset to %u.\n",
- (unsigned int)old_offset + data_len ));
- return False;
- }
-
- if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in, 0)) {
- DEBUG(0,("api_pipe_auth_process: failed to unmarshall RPC_HDR_AUTH.\n"));
- return False;
- }
+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in, 0)) {
+ DEBUG(0,("api_pipe_ntlmssp_auth_process: failed to unmarshall RPC_HDR_AUTH.\n"));
+ *pstatus = NT_STATUS_INVALID_PARAMETER;
+ return False;
}
- if (auth_verify) {
- RPC_AUTH_NTLMSSP_CHK ntlmssp_chk;
- char *req_data = prs_data_p(rpc_in) + prs_offset(rpc_in) + 4;
-
- DEBUG(5,("api_pipe_auth_process: auth %d\n", prs_offset(rpc_in) + 4));
-
- /*
- * Ensure we have RPC_AUTH_NTLMSSP_CHK_LEN - 4 more bytes in the
- * incoming buffer.
- */
- if(prs_mem_get(rpc_in, RPC_AUTH_NTLMSSP_CHK_LEN - 4) == NULL) {
- DEBUG(0,("api_pipe_auth_process: missing %d bytes in buffer.\n",
- RPC_AUTH_NTLMSSP_CHK_LEN - 4 ));
- return False;
- }
-
- NTLMSSPcalc_p(p, (uchar*)req_data, RPC_AUTH_NTLMSSP_CHK_LEN - 4);
- if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &ntlmssp_chk, rpc_in, 0)) {
- DEBUG(0,("api_pipe_auth_process: failed to unmarshall RPC_AUTH_NTLMSSP_CHK.\n"));
- return False;
- }
-
- if (!rpc_auth_ntlmssp_chk(&ntlmssp_chk, crc32, p->ntlmssp_seq_num)) {
- DEBUG(0,("api_pipe_auth_process: NTLMSSP check failed.\n"));
+ auth_blob.data = prs_data_p(rpc_in) + prs_offset(rpc_in);
+ auth_blob.length = auth_len;
+
+ switch (p->auth.auth_level) {
+ case PIPE_AUTH_LEVEL_PRIVACY:
+ /* Data is encrypted. */
+ *pstatus = ntlmssp_unseal_packet(a->ntlmssp_state,
+ data, data_len,
+ full_packet_data,
+ full_packet_data_len,
+ &auth_blob);
+ if (!NT_STATUS_IS_OK(*pstatus)) {
+ return False;
+ }
+ break;
+ case PIPE_AUTH_LEVEL_INTEGRITY:
+ /* Data is signed. */
+ *pstatus = ntlmssp_check_packet(a->ntlmssp_state,
+ data, data_len,
+ full_packet_data,
+ full_packet_data_len,
+ &auth_blob);
+ if (!NT_STATUS_IS_OK(*pstatus)) {
+ return False;
+ }
+ break;
+ default:
+ *pstatus = NT_STATUS_INVALID_PARAMETER;
return False;
- }
}
/*
* Return the current pointer to the data offset.
*/
- if(!prs_set_offset(rpc_in, old_offset)) {
+ if(!prs_set_offset(rpc_in, save_offset)) {
DEBUG(0,("api_pipe_auth_process: failed to set offset back to %u\n",
- (unsigned int)old_offset ));
+ (unsigned int)save_offset ));
+ *pstatus = NT_STATUS_INVALID_PARAMETER;
return False;
}
+ /*
+ * Remember the padding length. We must remove it from the real data
+ * stream once the sign/seal is done.
+ */
+
+ *p_ss_padding_len = auth_info.auth_pad_len;
+
return True;
}
/****************************************************************************
Deal with schannel processing on an RPC request.
****************************************************************************/
-BOOL api_pipe_netsec_process(pipes_struct *p, prs_struct *rpc_in)
+
+BOOL api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss_padding_len)
{
- /*
- * We always negotiate the following two bits....
- */
- int data_len;
- int auth_len;
- uint32 old_offset;
+ uint32 data_len;
+ uint32 auth_len;
+ uint32 save_offset = prs_offset(rpc_in);
RPC_HDR_AUTH auth_info;
- RPC_AUTH_NETSEC_CHK netsec_chk;
-
+ RPC_AUTH_SCHANNEL_CHK schannel_chk;
auth_len = p->hdr.auth_len;
- if (auth_len != RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN) {
- DEBUG(0,("Incorrect auth_len %d.\n", auth_len ));
+ if (auth_len != RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN) {
+ DEBUG(0,("Incorrect auth_len %u.\n", (unsigned int)auth_len ));
return False;
}
@@ -1364,16 +1974,21 @@ BOOL api_pipe_netsec_process(pipes_struct *p, prs_struct *rpc_in)
* preceeding the auth_data.
*/
+ if (p->hdr.frag_len < RPC_HEADER_LEN + RPC_HDR_REQ_LEN + RPC_HDR_AUTH_LEN + auth_len) {
+ DEBUG(0,("Incorrect frag %u, auth %u.\n",
+ (unsigned int)p->hdr.frag_len,
+ (unsigned int)auth_len ));
+ return False;
+ }
+
data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
RPC_HDR_AUTH_LEN - auth_len;
DEBUG(5,("data %d auth %d\n", data_len, auth_len));
- old_offset = prs_offset(rpc_in);
-
- if(!prs_set_offset(rpc_in, old_offset + data_len)) {
+ if(!prs_set_offset(rpc_in, RPC_HDR_REQ_LEN + data_len)) {
DEBUG(0,("cannot move offset to %u.\n",
- (unsigned int)old_offset + data_len ));
+ (unsigned int)RPC_HDR_REQ_LEN + data_len ));
return False;
}
@@ -1382,34 +1997,22 @@ BOOL api_pipe_netsec_process(pipes_struct *p, prs_struct *rpc_in)
return False;
}
- if (auth_info.auth_type != NETSEC_AUTH_TYPE) {
+ if (auth_info.auth_type != RPC_SCHANNEL_AUTH_TYPE) {
DEBUG(0,("Invalid auth info %d on schannel\n",
auth_info.auth_type));
return False;
}
- if (auth_info.auth_level == RPC_PIPE_AUTH_SEAL_LEVEL) {
- p->netsec_auth.auth_flags = AUTH_PIPE_NETSEC|AUTH_PIPE_SIGN|AUTH_PIPE_SEAL;
- } else if (auth_info.auth_level == RPC_PIPE_AUTH_SIGN_LEVEL) {
- p->netsec_auth.auth_flags = AUTH_PIPE_NETSEC|AUTH_PIPE_SIGN;
- } else {
- DEBUG(0,("Invalid auth level %d on schannel\n",
- auth_info.auth_level));
- return False;
- }
-
- if(!smb_io_rpc_auth_netsec_chk("", RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN,
- &netsec_chk, rpc_in, 0))
- {
- DEBUG(0,("failed to unmarshal RPC_AUTH_NETSEC_CHK.\n"));
+ if(!smb_io_rpc_auth_schannel_chk("", RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN, &schannel_chk, rpc_in, 0)) {
+ DEBUG(0,("failed to unmarshal RPC_AUTH_SCHANNEL_CHK.\n"));
return False;
}
- if (!netsec_decode(&p->netsec_auth,
- p->netsec_auth.auth_flags,
+ if (!schannel_decode(p->auth.a_u.schannel_auth,
+ p->auth.auth_level,
SENDER_IS_INITIATOR,
- &netsec_chk,
- prs_data_p(rpc_in)+old_offset, data_len)) {
+ &schannel_chk,
+ prs_data_p(rpc_in)+RPC_HDR_REQ_LEN, data_len)) {
DEBUG(3,("failed to decode PDU\n"));
return False;
}
@@ -1418,14 +2021,21 @@ BOOL api_pipe_netsec_process(pipes_struct *p, prs_struct *rpc_in)
* Return the current pointer to the data offset.
*/
- if(!prs_set_offset(rpc_in, old_offset)) {
+ if(!prs_set_offset(rpc_in, save_offset)) {
DEBUG(0,("failed to set offset back to %u\n",
- (unsigned int)old_offset ));
+ (unsigned int)save_offset ));
return False;
}
/* The sequence number gets incremented on both send and receive. */
- p->netsec_auth.seq_num++;
+ p->auth.a_u.schannel_auth->seq_num++;
+
+ /*
+ * Remember the padding length. We must remove it from the real data
+ * stream once the sign/seal is done.
+ */
+
+ *p_ss_padding_len = auth_info.auth_pad_len;
return True;
}
@@ -1436,7 +2046,9 @@ BOOL api_pipe_netsec_process(pipes_struct *p, prs_struct *rpc_in)
struct current_user *get_current_user(struct current_user *user, pipes_struct *p)
{
- if (p->ntlmssp_auth_validated) {
+ if (p->pipe_bound &&
+ (p->auth.auth_type == PIPE_AUTH_TYPE_NTLMSSP ||
+ (p->auth.auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP))) {
memcpy(user, &p->pipe_user, sizeof(struct current_user));
} else {
memcpy(user, &current_user, sizeof(struct current_user));
@@ -1470,7 +2082,7 @@ static PIPE_RPC_FNS* find_pipe_fns_by_context( PIPE_RPC_FNS *list, uint32 contex
}
/****************************************************************************
- memory cleanup
+ Memory cleanup.
****************************************************************************/
void free_pipe_rpc_context( PIPE_RPC_FNS *list )
@@ -1496,14 +2108,17 @@ void free_pipe_rpc_context( PIPE_RPC_FNS *list )
BOOL api_pipe_request(pipes_struct *p)
{
BOOL ret = False;
+ BOOL changed_user = False;
PIPE_RPC_FNS *pipe_fns;
- if (p->ntlmssp_auth_validated) {
-
+ if (p->pipe_bound &&
+ ((p->auth.auth_type == PIPE_AUTH_TYPE_NTLMSSP) ||
+ (p->auth.auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP))) {
if(!become_authenticated_pipe_user(p)) {
prs_mem_free(&p->out_data.rdata);
return False;
}
+ changed_user = True;
}
DEBUG(5, ("Requested \\PIPE\\%s\n", p->name));
@@ -1522,8 +2137,9 @@ BOOL api_pipe_request(pipes_struct *p)
p->hdr_req.context_id, p->name));
}
- if(p->ntlmssp_auth_validated)
+ if (changed_user) {
unbecome_authenticated_pipe_user();
+ }
return ret;
}
@@ -1649,6 +2265,9 @@ void get_pipe_fns( int idx, struct api_struct **fns, int *n_fns )
case PI_EVENTLOG:
eventlog_get_pipe_fns( &cmds, &n_cmds );
break;
+ case PI_NTSVCS:
+ ntsvcs_get_pipe_fns( &cmds, &n_cmds );
+ break;
#ifdef DEVELOPER
case PI_ECHO:
echo_get_pipe_fns( &cmds, &n_cmds );
@@ -1663,5 +2282,3 @@ void get_pipe_fns( int idx, struct api_struct **fns, int *n_fns )
return;
}
-
-
diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c
index 83b78f8d2f6..205223190b4 100644
--- a/source3/rpc_server/srv_pipe_hnd.c
+++ b/source3/rpc_server/srv_pipe_hnd.c
@@ -2,8 +2,8 @@
* Unix SMB/CIFS implementation.
* RPC Pipe client / server routines
* Copyright (C) Andrew Tridgell 1992-1998,
- * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
- * Copyright (C) Jeremy Allison 1999.
+ * Largely re-written : 2005
+ * Copyright (C) Jeremy Allison 1998 - 2005
*
* 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
@@ -106,10 +106,11 @@ static int pipe_handle_offset;
void set_pipe_handle_offset(int max_open_files)
{
- if(max_open_files < 0x7000)
- pipe_handle_offset = 0x7000;
- else
- pipe_handle_offset = max_open_files + 10; /* For safety. :-) */
+ if(max_open_files < 0x7000) {
+ pipe_handle_offset = 0x7000;
+ } else {
+ pipe_handle_offset = max_open_files + 10; /* For safety. :-) */
+ }
}
/****************************************************************************
@@ -128,8 +129,9 @@ void reset_chain_p(void)
void init_rpc_pipe_hnd(void)
{
bmap = bitmap_allocate(MAX_OPEN_PIPES);
- if (!bmap)
+ if (!bmap) {
exit_server("out of memory in init_rpc_pipe_hnd");
+ }
}
/****************************************************************************
@@ -154,7 +156,7 @@ static BOOL pipe_init_outgoing_data(pipes_struct *p)
* Initialize the outgoing RPC data buffer.
* we will use this as the raw data area for replying to rpc requests.
*/
- if(!prs_init(&o_data->rdata, MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) {
+ if(!prs_init(&o_data->rdata, RPC_MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) {
DEBUG(0,("pipe_init_outgoing_data: malloc fail.\n"));
return False;
}
@@ -177,8 +179,9 @@ smb_np_struct *open_rpc_pipe_p(char *pipe_name,
DEBUG(4,("Open pipe requested %s (pipes_open=%d)\n",
pipe_name, pipes_open));
- if (strstr(pipe_name, "spoolss"))
+ if (strstr(pipe_name, "spoolss")) {
is_spoolss_pipe = True;
+ }
if (is_spoolss_pipe && current_spoolss_pipes_open >= MAX_OPEN_SPOOLSS_PIPES) {
DEBUG(10,("open_rpc_pipe_p: spooler bug workaround. Denying open on pipe %s\n",
@@ -189,8 +192,10 @@ smb_np_struct *open_rpc_pipe_p(char *pipe_name,
/* not repeating pipe numbers makes it easier to track things in
log files and prevents client bugs where pipe numbers are reused
over connection restarts */
- if (next_pipe == 0)
+
+ if (next_pipe == 0) {
next_pipe = (sys_getpid() ^ time(NULL)) % MAX_OPEN_PIPES;
+ }
i = bitmap_find(bmap, next_pipe);
@@ -201,8 +206,9 @@ smb_np_struct *open_rpc_pipe_p(char *pipe_name,
next_pipe = (i+1) % MAX_OPEN_PIPES;
- for (p = Pipes; p; p = p->next)
+ for (p = Pipes; p; p = p->next) {
DEBUG(5,("open_rpc_pipe_p: name %s pnum=%x\n", p->name, p->pnum));
+ }
p = SMB_MALLOC_P(smb_np_struct);
if (!p) {
@@ -259,8 +265,9 @@ smb_np_struct *open_rpc_pipe_p(char *pipe_name,
chain_p = p;
/* Iterate over p_it as a temp variable, to display all open pipes */
- for (p_it = Pipes; p_it; p_it = p_it->next)
+ for (p_it = Pipes; p_it; p_it = p_it->next) {
DEBUG(5,("open pipes: name %s pnum=%x\n", p_it->name, p_it->pnum));
+ }
return chain_p;
}
@@ -297,9 +304,17 @@ static void *make_internal_rpc_pipe_p(char *pipe_name,
return NULL;
}
+ if ((p->pipe_state_mem_ctx = talloc_init("pipe_state %s %p", pipe_name, p)) == NULL) {
+ DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n"));
+ talloc_destroy(p->mem_ctx);
+ SAFE_FREE(p);
+ return NULL;
+ }
+
if (!init_pipe_handle_list(p, pipe_name)) {
DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n"));
talloc_destroy(p->mem_ctx);
+ talloc_destroy(p->pipe_state_mem_ctx);
SAFE_FREE(p);
return NULL;
}
@@ -311,8 +326,10 @@ static void *make_internal_rpc_pipe_p(char *pipe_name,
* change the type to UNMARSALLING before processing the stream.
*/
- if(!prs_init(&p->in_data.data, MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) {
+ if(!prs_init(&p->in_data.data, RPC_MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) {
DEBUG(0,("open_rpc_pipe_p: malloc fail for in_data struct.\n"));
+ talloc_destroy(p->mem_ctx);
+ talloc_destroy(p->pipe_state_mem_ctx);
return NULL;
}
@@ -325,12 +342,6 @@ static void *make_internal_rpc_pipe_p(char *pipe_name,
p->vuid = vuid;
- p->ntlmssp_chal_flags = 0;
- p->ntlmssp_auth_validated = False;
- p->ntlmssp_auth_requested = False;
-
- p->pipe_bound = False;
- p->fault_state = False;
p->endian = RPC_LITTLE_ENDIAN;
ZERO_STRUCT(p->pipe_user);
@@ -345,21 +356,6 @@ static void *make_internal_rpc_pipe_p(char *pipe_name,
}
/*
- * Initialize the incoming RPC struct.
- */
-
- p->in_data.pdu_needed_len = 0;
- p->in_data.pdu_received_len = 0;
-
- /*
- * Initialize the outgoing RPC struct.
- */
-
- p->out_data.current_pdu_len = 0;
- p->out_data.current_pdu_sent = 0;
- p->out_data.data_sent_length = 0;
-
- /*
* Initialize the outgoing RPC data buffer with no memory.
*/
prs_init(&p->out_data.rdata, 0, p->mem_ctx, MARSHALL);
@@ -504,7 +500,7 @@ static ssize_t unmarshall_rpc_header(pipes_struct *p)
* Ensure that the pdu length is sane.
*/
- if((p->hdr.frag_len < RPC_HEADER_LEN) || (p->hdr.frag_len > MAX_PDU_FRAG_LEN)) {
+ if((p->hdr.frag_len < RPC_HEADER_LEN) || (p->hdr.frag_len > RPC_MAX_PDU_FRAG_LEN)) {
DEBUG(0,("unmarshall_rpc_header: assert on frag length failed.\n"));
set_incoming_fault(p);
prs_mem_free(&rpc_in);
@@ -514,18 +510,8 @@ static ssize_t unmarshall_rpc_header(pipes_struct *p)
DEBUG(10,("unmarshall_rpc_header: type = %u, flags = %u\n", (unsigned int)p->hdr.pkt_type,
(unsigned int)p->hdr.flags ));
- /*
- * Adjust for the header we just ate.
- */
- p->in_data.pdu_received_len = 0;
p->in_data.pdu_needed_len = (uint32)p->hdr.frag_len - RPC_HEADER_LEN;
- /*
- * Null the data we just ate.
- */
-
- memset((char *)&p->in_data.current_in_pdu[0], '\0', RPC_HEADER_LEN);
-
prs_mem_free(&rpc_in);
return 0; /* No extra data processed. */
@@ -540,12 +526,13 @@ static void free_pipe_context(pipes_struct *p)
{
if (p->mem_ctx) {
DEBUG(3,("free_pipe_context: destroying talloc pool of size "
- "%llu\n", talloc_total_size(p->mem_ctx) ));
+ "%lu\n", (unsigned long)talloc_total_size(p->mem_ctx) ));
talloc_free_children(p->mem_ctx);
} else {
p->mem_ctx = talloc_init("pipe %s %p", p->name, p);
- if (p->mem_ctx == NULL)
+ if (p->mem_ctx == NULL) {
p->fault_state = True;
+ }
}
}
@@ -556,9 +543,9 @@ static void free_pipe_context(pipes_struct *p)
static BOOL process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
{
- BOOL auth_verify = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) != 0);
+ uint32 ss_padding_len = 0;
size_t data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
- (auth_verify ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len;
+ (p->hdr.auth_len ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len;
if(!p->pipe_bound) {
DEBUG(0,("process_request_pdu: rpc request with no bind.\n"));
@@ -581,29 +568,40 @@ static BOOL process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
return False;
}
- if(p->ntlmssp_auth_validated && !api_pipe_auth_process(p, rpc_in_p)) {
- DEBUG(0,("process_request_pdu: failed to do auth processing.\n"));
- set_incoming_fault(p);
- return False;
- }
+ switch(p->auth.auth_type) {
+ case PIPE_AUTH_TYPE_NONE:
+ break;
- if (p->ntlmssp_auth_requested && !p->ntlmssp_auth_validated) {
+ case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
+ case PIPE_AUTH_TYPE_NTLMSSP:
+ {
+ NTSTATUS status;
+ if(!api_pipe_ntlmssp_auth_process(p, rpc_in_p, &ss_padding_len, &status)) {
+ DEBUG(0,("process_request_pdu: failed to do auth processing.\n"));
+ DEBUG(0,("process_request_pdu: error was %s.\n", nt_errstr(status) ));
+ set_incoming_fault(p);
+ return False;
+ }
+ break;
+ }
- /*
- * Authentication _was_ requested and it already failed.
- */
+ case PIPE_AUTH_TYPE_SCHANNEL:
+ if (!api_pipe_schannel_process(p, rpc_in_p, &ss_padding_len)) {
+ DEBUG(3,("process_request_pdu: failed to do schannel processing.\n"));
+ set_incoming_fault(p);
+ return False;
+ }
+ break;
- DEBUG(0,("process_request_pdu: RPC request received on pipe %s "
- "where authentication failed. Denying the request.\n",
- p->name));
- set_incoming_fault(p);
- return False;
+ default:
+ DEBUG(0,("process_request_pdu: unknown auth type %u set.\n", (unsigned int)p->auth.auth_type ));
+ set_incoming_fault(p);
+ return False;
}
- if (p->netsec_auth_validated && !api_pipe_netsec_process(p, rpc_in_p)) {
- DEBUG(3,("process_request_pdu: failed to do schannel processing.\n"));
- set_incoming_fault(p);
- return False;
+ /* Now we've done the sign/seal we can remove any padding data. */
+ if (data_len > ss_padding_len) {
+ data_len -= ss_padding_len;
}
/*
@@ -643,8 +641,7 @@ static BOOL process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
* size as the current offset.
*/
- if(!prs_set_buffer_size(&p->in_data.data, prs_offset(&p->in_data.data)))
- {
+ if(!prs_set_buffer_size(&p->in_data.data, prs_offset(&p->in_data.data))) {
DEBUG(0,("process_request_pdu: Call to prs_set_buffer_size failed!\n"));
set_incoming_fault(p);
return False;
@@ -664,8 +661,9 @@ static BOOL process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
free_pipe_context(p);
- if(pipe_init_outgoing_data(p))
+ if(pipe_init_outgoing_data(p)) {
ret = api_pipe_request(p);
+ }
free_pipe_context(p);
@@ -690,11 +688,11 @@ static BOOL process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
already been parsed and stored in p->hdr.
****************************************************************************/
-static ssize_t process_complete_pdu(pipes_struct *p)
+static void process_complete_pdu(pipes_struct *p)
{
prs_struct rpc_in;
- size_t data_len = p->in_data.pdu_received_len;
- char *data_p = (char *)&p->in_data.current_in_pdu[0];
+ size_t data_len = p->in_data.pdu_received_len - RPC_HEADER_LEN;
+ char *data_p = (char *)&p->in_data.current_in_pdu[RPC_HEADER_LEN];
BOOL reply = False;
if(p->fault_state) {
@@ -702,7 +700,7 @@ static ssize_t process_complete_pdu(pipes_struct *p)
p->name ));
set_incoming_fault(p);
setup_fault_pdu(p, NT_STATUS(0x1c010002));
- return (ssize_t)data_len;
+ return;
}
prs_init( &rpc_in, 0, p->mem_ctx, UNMARSHALL);
@@ -722,19 +720,28 @@ static ssize_t process_complete_pdu(pipes_struct *p)
switch (p->hdr.pkt_type) {
case RPC_BIND:
- case RPC_ALTCONT:
/*
* We assume that a pipe bind is only in one pdu.
*/
- if(pipe_init_outgoing_data(p))
+ if(pipe_init_outgoing_data(p)) {
reply = api_pipe_bind_req(p, &rpc_in);
+ }
+ break;
+ case RPC_ALTCONT:
+ /*
+ * We assume that a pipe bind is only in one pdu.
+ */
+ if(pipe_init_outgoing_data(p)) {
+ reply = api_pipe_alter_context(p, &rpc_in);
+ }
break;
- case RPC_BINDRESP:
+ case RPC_AUTH3:
/*
- * We assume that a pipe bind_resp is only in one pdu.
+ * The third packet in an NTLMSSP auth exchange.
*/
- if(pipe_init_outgoing_data(p))
- reply = api_pipe_bind_auth_resp(p, &rpc_in);
+ if(pipe_init_outgoing_data(p)) {
+ reply = api_pipe_bind_auth3(p, &rpc_in);
+ }
break;
case RPC_REQUEST:
reply = process_request_pdu(p, &rpc_in);
@@ -761,7 +768,6 @@ static ssize_t process_complete_pdu(pipes_struct *p)
}
prs_mem_free(&rpc_in);
- return (ssize_t)data_len;
}
/****************************************************************************
@@ -770,8 +776,7 @@ static ssize_t process_complete_pdu(pipes_struct *p)
static ssize_t process_incoming_data(pipes_struct *p, char *data, size_t n)
{
- size_t data_to_copy = MIN(n, MAX_PDU_FRAG_LEN - p->in_data.pdu_received_len);
- size_t old_pdu_received_len = p->in_data.pdu_received_len;
+ size_t data_to_copy = MIN(n, RPC_MAX_PDU_FRAG_LEN - p->in_data.pdu_received_len);
DEBUG(10,("process_incoming_data: Start: pdu_received_len = %u, pdu_needed_len = %u, incoming data = %u\n",
(unsigned int)p->in_data.pdu_received_len, (unsigned int)p->in_data.pdu_needed_len,
@@ -812,8 +817,9 @@ incoming data size = %u\n", (unsigned int)p->in_data.pdu_received_len, (unsigned
* data we need, then loop again.
*/
- if(p->in_data.pdu_needed_len == 0)
+ if(p->in_data.pdu_needed_len == 0) {
return unmarshall_rpc_header(p);
+ }
/*
* Ok - at this point we have a valid RPC_HEADER in p->hdr.
@@ -824,24 +830,27 @@ incoming data size = %u\n", (unsigned int)p->in_data.pdu_received_len, (unsigned
/*
* Copy as much of the data as we need into the current_in_pdu buffer.
+ * pdu_needed_len becomes zero when we have a complete pdu.
*/
memcpy( (char *)&p->in_data.current_in_pdu[p->in_data.pdu_received_len], data, data_to_copy);
p->in_data.pdu_received_len += data_to_copy;
+ p->in_data.pdu_needed_len -= data_to_copy;
/*
* Do we have a complete PDU ?
- * (return the nym of bytes handled in the call)
+ * (return the number of bytes handled in the call)
*/
- if(p->in_data.pdu_received_len == p->in_data.pdu_needed_len)
- return process_complete_pdu(p) - old_pdu_received_len;
+ if(p->in_data.pdu_needed_len == 0) {
+ process_complete_pdu(p);
+ return data_to_copy;
+ }
DEBUG(10,("process_incoming_data: not a complete PDU yet. pdu_received_len = %u, pdu_needed_len = %u\n",
(unsigned int)p->in_data.pdu_received_len, (unsigned int)p->in_data.pdu_needed_len ));
return (ssize_t)data_to_copy;
-
}
/****************************************************************************
@@ -878,8 +887,9 @@ static ssize_t write_to_internal_pipe(void *np_conn, char *data, size_t n)
DEBUG(10,("write_to_pipe: data_used = %d\n", (int)data_used ));
- if(data_used < 0)
+ if(data_used < 0) {
return -1;
+ }
data_left -= data_used;
data += data_used;
@@ -948,9 +958,9 @@ static ssize_t read_from_internal_pipe(void *np_conn, char *data, size_t n,
* authentications failing. Just ignore it so things work.
*/
- if(n > MAX_PDU_FRAG_LEN) {
+ if(n > RPC_MAX_PDU_FRAG_LEN) {
DEBUG(5,("read_from_pipe: too large read (%u) requested on \
-pipe %s. We can only service %d sized reads.\n", (unsigned int)n, p->name, MAX_PDU_FRAG_LEN ));
+pipe %s. We can only service %d sized reads.\n", (unsigned int)n, p->name, RPC_MAX_PDU_FRAG_LEN ));
}
/*
@@ -1019,8 +1029,9 @@ returning %d bytes.\n", p->name, (unsigned int)p->out_data.current_pdu_len,
BOOL wait_rpc_pipe_hnd_state(smb_np_struct *p, uint16 priority)
{
- if (p == NULL)
+ if (p == NULL) {
return False;
+ }
if (p->open) {
DEBUG(3,("wait_rpc_pipe_hnd_state: Setting pipe wait state priority=%x on pipe (name=%s)\n",
@@ -1043,8 +1054,9 @@ BOOL wait_rpc_pipe_hnd_state(smb_np_struct *p, uint16 priority)
BOOL set_rpc_pipe_hnd_state(smb_np_struct *p, uint16 device_state)
{
- if (p == NULL)
+ if (p == NULL) {
return False;
+ }
if (p->open) {
DEBUG(3,("set_rpc_pipe_hnd_state: Setting pipe device state=%x on pipe (name=%s)\n",
@@ -1121,9 +1133,18 @@ static BOOL close_internal_rpc_pipe_hnd(void *np_conn)
prs_mem_free(&p->out_data.rdata);
prs_mem_free(&p->in_data.data);
- if (p->mem_ctx)
+ if (p->auth.auth_data_free_func) {
+ (*p->auth.auth_data_free_func)(&p->auth);
+ }
+
+ if (p->mem_ctx) {
talloc_destroy(p->mem_ctx);
-
+ }
+
+ if (p->pipe_state_mem_ctx) {
+ talloc_destroy(p->pipe_state_mem_ctx);
+ }
+
free_pipe_rpc_context( p->contexts );
/* Free the handles database. */
@@ -1152,8 +1173,9 @@ smb_np_struct *get_rpc_pipe_p(char *buf, int where)
{
int pnum = SVAL(buf,where);
- if (chain_p)
+ if (chain_p) {
return chain_p;
+ }
return get_rpc_pipe(pnum);
}
@@ -1168,9 +1190,10 @@ smb_np_struct *get_rpc_pipe(int pnum)
DEBUG(4,("search for pipe pnum=%x\n", pnum));
- for (p=Pipes;p;p=p->next)
+ for (p=Pipes;p;p=p->next) {
DEBUG(5,("pipe name %s pnum=%x (pipes_open=%d)\n",
p->name, p->pnum, pipes_open));
+ }
for (p=Pipes;p;p=p->next) {
if (p->pnum == pnum) {
diff --git a/source3/rpc_server/srv_reg.c b/source3/rpc_server/srv_reg.c
index 871b1a9f121..17725240387 100644
--- a/source3/rpc_server/srv_reg.c
+++ b/source3/rpc_server/srv_reg.c
@@ -383,7 +383,7 @@ static BOOL api_reg_restore_key(pipes_struct *p)
if(!reg_io_q_restore_key("", &q_u, data, 0))
return False;
-
+
r_u.status = _reg_restore_key(p, &q_u, &r_u);
if(!reg_io_r_restore_key("", &r_u, rdata, 0))
@@ -393,7 +393,7 @@ static BOOL api_reg_restore_key(pipes_struct *p)
}
/*******************************************************************
- ******************************************************************/
+ ********************************************************************/
static BOOL api_reg_save_key(pipes_struct *p)
{
@@ -417,6 +417,57 @@ static BOOL api_reg_save_key(pipes_struct *p)
}
/*******************************************************************
+ api_reg_open_hkpd
+ ********************************************************************/
+
+static BOOL api_reg_open_hkpd(pipes_struct *p)
+{
+ REG_Q_OPEN_HIVE q_u;
+ REG_R_OPEN_HIVE r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the reg open */
+ if(!reg_io_q_open_hive("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _reg_open_hkpd(p, &q_u, &r_u);
+
+ if(!reg_io_r_open_hive("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ api_reg_open_hkpd
+ ********************************************************************/
+static BOOL api_reg_open_hkpt(pipes_struct *p)
+{
+ REG_Q_OPEN_HIVE q_u;
+ REG_R_OPEN_HIVE r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ /* grab the reg open */
+ if(!reg_io_q_open_hive("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _reg_open_hkpt(p, &q_u, &r_u);
+
+ if(!reg_io_r_open_hive("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
******************************************************************/
static BOOL api_reg_create_key_ex(pipes_struct *p)
@@ -573,6 +624,8 @@ static struct api_struct api_reg_cmds[] =
{ "REG_OPEN_ENTRY" , REG_OPEN_ENTRY , api_reg_open_entry },
{ "REG_OPEN_HKCR" , REG_OPEN_HKCR , api_reg_open_hkcr },
{ "REG_OPEN_HKLM" , REG_OPEN_HKLM , api_reg_open_hklm },
+ { "REG_OPEN_HKPD" , REG_OPEN_HKPD , api_reg_open_hkpd },
+ { "REG_OPEN_HKPT" , REG_OPEN_HKPT , api_reg_open_hkpt },
{ "REG_OPEN_HKU" , REG_OPEN_HKU , api_reg_open_hku },
{ "REG_ENUM_KEY" , REG_ENUM_KEY , api_reg_enum_key },
{ "REG_ENUM_VALUE" , REG_ENUM_VALUE , api_reg_enum_value },
diff --git a/source3/rpc_server/srv_reg_nt.c b/source3/rpc_server/srv_reg_nt.c
index a405948864b..4db5ed0ed62 100644
--- a/source3/rpc_server/srv_reg_nt.c
+++ b/source3/rpc_server/srv_reg_nt.c
@@ -33,62 +33,9 @@
#define OUR_HANDLE(hnd) (((hnd)==NULL)?"NULL":(IVAL((hnd)->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER")), \
((unsigned int)IVAL((hnd)->data5,4)),((unsigned int)sys_getpid())
+static struct generic_mapping reg_generic_map =
+ { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL };
-static struct generic_mapping reg_generic_map = { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL };
-
-/********************************************************************
-********************************************************************/
-
-NTSTATUS registry_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token,
- uint32 access_desired, uint32 *access_granted )
-{
- NTSTATUS result;
-
- if ( geteuid() == sec_initial_uid() ) {
- DEBUG(5,("registry_access_check: access check bypassed for 'root'\n"));
- *access_granted = REG_KEY_ALL;
- return NT_STATUS_OK;
- }
-
- se_map_generic( &access_desired, &reg_generic_map );
- se_access_check( sec_desc, token, access_desired, access_granted, &result );
-
- return result;
-}
-
-/********************************************************************
-********************************************************************/
-
-SEC_DESC* construct_registry_sd( TALLOC_CTX *ctx )
-{
- SEC_ACE ace[2];
- SEC_ACCESS mask;
- size_t i = 0;
- SEC_DESC *sd;
- SEC_ACL *acl;
- uint32 sd_size;
-
- /* basic access for Everyone */
-
- init_sec_access(&mask, REG_KEY_READ );
- init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-
- /* Full Access 'BUILTIN\Administrators' */
-
- init_sec_access(&mask, REG_KEY_ALL );
- init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-
-
- /* create the security descriptor */
-
- if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
- return NULL;
-
- if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
- return NULL;
-
- return sd;
-}
/******************************************************************
free() function for REGISTRY_KEY
@@ -96,9 +43,7 @@ SEC_DESC* construct_registry_sd( TALLOC_CTX *ctx )
static void free_regkey_info(void *ptr)
{
- REGISTRY_KEY *info = (REGISTRY_KEY*)ptr;
-
- SAFE_FREE(info);
+ TALLOC_FREE( ptr );
}
/******************************************************************
@@ -126,89 +71,38 @@ static REGISTRY_KEY *find_regkey_index_by_hnd(pipes_struct *p, POLICY_HND *hnd)
HK[LM|U]\<key>\<key>\...
*******************************************************************/
-static WERROR open_registry_key(pipes_struct *p, POLICY_HND *hnd, REGISTRY_KEY *parent,
- const char *subkeyname, uint32 access_granted )
+static WERROR open_registry_key( pipes_struct *p, POLICY_HND *hnd,
+ REGISTRY_KEY **keyinfo, REGISTRY_KEY *parent,
+ const char *subkeyname, uint32 access_desired )
{
- REGISTRY_KEY *regkey = NULL;
+ pstring keypath;
+ int path_len;
WERROR result = WERR_OK;
- REGSUBKEY_CTR *subkeys = NULL;
- pstring subkeyname2;
- int subkey_len;
-
- DEBUG(7,("open_registry_key: name = [%s][%s]\n",
- parent ? parent->name : "NULL", subkeyname));
-
- /* strip any trailing '\'s */
- pstrcpy( subkeyname2, subkeyname );
- subkey_len = strlen ( subkeyname2 );
- if ( subkey_len && subkeyname2[subkey_len-1] == '\\' )
- subkeyname2[subkey_len-1] = '\0';
- if ((regkey=SMB_MALLOC_P(REGISTRY_KEY)) == NULL)
- return WERR_NOMEM;
-
- ZERO_STRUCTP( regkey );
-
- /*
- * very crazy, but regedit.exe on Win2k will attempt to call
- * REG_OPEN_ENTRY with a keyname of "". We should return a new
- * (second) handle here on the key->name. regedt32.exe does
- * not do this stupidity. --jerry
- */
-
- if ( !subkey_len ) {
- pstrcpy( regkey->name, parent->name );
- }
- else {
- pstrcpy( regkey->name, "" );
- if ( parent ) {
- pstrcat( regkey->name, parent->name );
- pstrcat( regkey->name, "\\" );
- }
- pstrcat( regkey->name, subkeyname2 );
- }
+ /* create a full registry path and strip any trailing '\'
+ characters */
+
+ pstr_sprintf( keypath, "%s%s%s",
+ parent ? parent->name : "",
+ parent ? "\\" : "",
+ subkeyname );
- /* Look up the table of registry I/O operations */
-
- if ( !(regkey->hook = reghook_cache_find( regkey->name )) ) {
- DEBUG(0,("open_registry_key: Failed to assigned a REGISTRY_HOOK to [%s]\n",
- regkey->name ));
- result = WERR_BADFILE;
- goto done;
- }
+ path_len = strlen( keypath );
+ if ( path_len && keypath[path_len-1] == '\\' )
+ keypath[path_len-1] = '\0';
- /* check if the path really exists; failed is indicated by -1 */
- /* if the subkey count failed, bail out */
-
- if ( !(subkeys = TALLOC_ZERO_P( p->mem_ctx, REGSUBKEY_CTR )) ) {
- result = WERR_NOMEM;
- goto done;
- }
-
- if ( fetch_reg_keys( regkey, subkeys ) == -1 ) {
- result = WERR_BADFILE;
- goto done;
- }
+ /* now do the internal open */
- if ( !create_policy_hnd( p, hnd, free_regkey_info, regkey ) ) {
+ result = regkey_open_internal( keyinfo, keypath, p->pipe_user.nt_user_token, access_desired );
+ if ( !W_ERROR_IS_OK(result) )
+ return result;
+
+ if ( !create_policy_hnd( p, hnd, free_regkey_info, *keyinfo ) ) {
result = WERR_BADFILE;
- goto done;
+ TALLOC_FREE( *keyinfo );
}
- /* save the access mask */
-
- regkey->access_granted = access_granted;
-
-done:
- /* clean up */
-
- TALLOC_FREE( subkeys );
-
- if ( ! NT_STATUS_IS_OK(result) )
- SAFE_FREE( regkey );
- DEBUG(7,("open_registry_key: exit\n"));
-
return result;
}
@@ -332,43 +226,39 @@ WERROR _reg_close(pipes_struct *p, REG_Q_CLOSE *q_u, REG_R_CLOSE *r_u)
WERROR _reg_open_hklm(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
{
- SEC_DESC *sec_desc;
- uint32 access_granted = 0;
- NTSTATUS status;
+ REGISTRY_KEY *keyinfo;
- /* perform access checks */
- /* top level keys are done here without passing through the REGISTRY_HOOK api */
+ return open_registry_key( p, &r_u->pol, &keyinfo, NULL, KEY_HKLM, q_u->access );
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _reg_open_hkpd(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
+{
+ REGISTRY_KEY *keyinfo;
- if ( !(sec_desc = construct_registry_sd( p->mem_ctx )) )
- return WERR_NOMEM;
-
- status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
- if ( !NT_STATUS_IS_OK(status) )
- return ntstatus_to_werror( status );
-
- return open_registry_key( p, &r_u->pol, NULL, KEY_HKLM, access_granted );
+ return open_registry_key( p, &r_u->pol, &keyinfo, NULL, KEY_HKPD, q_u->access );
}
/*******************************************************************
********************************************************************/
-WERROR _reg_open_hkcr(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
+WERROR _reg_open_hkpt(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
{
- SEC_DESC *sec_desc;
- uint32 access_granted = 0;
- NTSTATUS status;
+ REGISTRY_KEY *keyinfo;
- /* perform access checks */
- /* top level keys are done here without passing through the REGISTRY_HOOK api */
+ return open_registry_key( p, &r_u->pol, &keyinfo, NULL, KEY_HKPT, q_u->access );
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+WERROR _reg_open_hkcr(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
+{
+ REGISTRY_KEY *keyinfo;
- if ( !(sec_desc = construct_registry_sd( p->mem_ctx )) )
- return WERR_NOMEM;
-
- status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
- if ( !NT_STATUS_IS_OK(status) )
- return ntstatus_to_werror( status );
-
- return open_registry_key( p, &r_u->pol, NULL, KEY_HKCR, access_granted );
+ return open_registry_key( p, &r_u->pol, &keyinfo, NULL, KEY_HKCR, q_u->access );
}
/*******************************************************************
@@ -376,21 +266,9 @@ WERROR _reg_open_hkcr(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_
WERROR _reg_open_hku(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u)
{
- SEC_DESC *sec_desc;
- uint32 access_granted = 0;
- NTSTATUS status;
-
- /* perform access checks */
- /* top level keys are done here without passing through the REGISTRY_HOOK api */
+ REGISTRY_KEY *keyinfo;
- if ( !(sec_desc = construct_registry_sd( p->mem_ctx )) )
- return WERR_NOMEM;
-
- status = registry_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
- if ( !NT_STATUS_IS_OK(status) )
- return ntstatus_to_werror( status );
-
- return open_registry_key( p, &r_u->pol, NULL, KEY_HKU, access_granted );
+ return open_registry_key( p, &r_u->pol, &keyinfo, NULL, KEY_HKU, q_u->access );
}
/*******************************************************************
@@ -401,9 +279,8 @@ WERROR _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY
{
fstring name;
REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->pol);
- REGISTRY_KEY *newkey;
- uint32 access_granted;
- WERROR result;
+ REGISTRY_KEY *newkey = NULL;
+ uint32 check_rights;
if ( !parent )
return WERR_BADFID;
@@ -412,29 +289,22 @@ WERROR _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY
/* check granted access first; what is the correct mask here? */
- if ( !(parent->access_granted & (SEC_RIGHTS_ENUM_SUBKEYS|SEC_RIGHTS_CREATE_SUBKEY|SEC_RIGHTS_QUERY_VALUE|SEC_RIGHTS_SET_VALUE)) )
+ check_rights = ( SEC_RIGHTS_ENUM_SUBKEYS|
+ SEC_RIGHTS_CREATE_SUBKEY|
+ SEC_RIGHTS_QUERY_VALUE|
+ SEC_RIGHTS_SET_VALUE);
+
+ if ( !(parent->access_granted & check_rights) )
return WERR_ACCESS_DENIED;
- /* open the key first to get the appropriate REGISTRY_HOOK
- and then check the premissions */
-
- if ( !W_ERROR_IS_OK(result = open_registry_key( p, &r_u->handle, parent, name, 0 )) )
- return result;
-
- newkey = find_regkey_index_by_hnd(p, &r_u->handle);
-
- /* finally allow the backend to check the access for the requested key */
-
- if ( !regkey_access_check( newkey, q_u->access, &access_granted, p->pipe_user.nt_user_token ) ) {
- close_registry_key( p, &r_u->handle );
- return WERR_ACCESS_DENIED;
- }
-
- /* if successful, save the granted access mask */
-
- newkey->access_granted = access_granted;
-
- return WERR_OK;
+ /*
+ * very crazy, but regedit.exe on Win2k will attempt to call
+ * REG_OPEN_ENTRY with a keyname of "". We should return a new
+ * (second) handle here on the key->name. regedt32.exe does
+ * not do this stupidity. --jerry
+ */
+
+ return open_registry_key( p, &r_u->handle, &newkey, parent, name, q_u->access );
}
/*******************************************************************
@@ -454,16 +324,93 @@ WERROR _reg_query_value(pipes_struct *p, REG_Q_QUERY_VALUE *q_u, REG_R_QUERY_VAL
return WERR_BADFID;
DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->name));
+ DEBUG(7,("_reg_info: policy key type = [%08x]\n", regkey->type));
rpcstr_pull(name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0);
- DEBUG(5,("reg_info: looking up value: [%s]\n", name));
+ DEBUG(5,("_reg_info: looking up value: [%s]\n", name));
if ( !(regvals = TALLOC_P( p->mem_ctx, REGVAL_CTR )) )
return WERR_NOMEM;
- for ( i=0; fetch_reg_values_specific(regkey, &val, i); i++ )
+ /* Handle QueryValue calls on HKEY_PERFORMANCE_DATA */
+ if(regkey->type == REG_KEY_HKPD)
+ {
+ if(strequal(name, "Global"))
+ {
+ uint32 outbuf_len;
+ prs_struct prs_hkpd;
+ prs_init(&prs_hkpd, q_u->bufsize, p->mem_ctx, MARSHALL);
+ status = reg_perfcount_get_hkpd(&prs_hkpd, q_u->bufsize, &outbuf_len, NULL);
+ regval_ctr_addvalue(regvals, "HKPD", REG_BINARY,
+ prs_hkpd.data_p, outbuf_len);
+ val = dup_registry_value(regval_ctr_specific_value(regvals, 0));
+ prs_mem_free(&prs_hkpd);
+ }
+ else if(strequal(name, "Counter 009"))
+ {
+ uint32 base_index;
+ uint32 buffer_size;
+ char *buffer;
+
+ buffer = NULL;
+ base_index = reg_perfcount_get_base_index();
+ buffer_size = reg_perfcount_get_counter_names(base_index, &buffer);
+ regval_ctr_addvalue(regvals, "Counter 009",
+ REG_MULTI_SZ, buffer, buffer_size);
+
+ val = dup_registry_value(regval_ctr_specific_value(regvals, 0));
+
+ if(buffer_size > 0)
+ {
+ SAFE_FREE(buffer);
+ status = WERR_OK;
+ }
+ }
+ else if(strequal(name, "Explain 009"))
+ {
+ uint32 base_index;
+ uint32 buffer_size;
+ char *buffer;
+
+ buffer = NULL;
+ base_index = reg_perfcount_get_base_index();
+ buffer_size = reg_perfcount_get_counter_help(base_index, &buffer);
+ regval_ctr_addvalue(regvals, "Explain 009",
+ REG_MULTI_SZ, buffer, buffer_size);
+
+ val = dup_registry_value(regval_ctr_specific_value(regvals, 0));
+
+ if(buffer_size > 0)
+ {
+ SAFE_FREE(buffer);
+ status = WERR_OK;
+ }
+ }
+ else if(isdigit(name[0]))
+ {
+ /* we probably have a request for a specific object here */
+ uint32 outbuf_len;
+ prs_struct prs_hkpd;
+ prs_init(&prs_hkpd, q_u->bufsize, p->mem_ctx, MARSHALL);
+ status = reg_perfcount_get_hkpd(&prs_hkpd, q_u->bufsize, &outbuf_len, name);
+ regval_ctr_addvalue(regvals, "HKPD", REG_BINARY,
+ prs_hkpd.data_p, outbuf_len);
+
+ val = dup_registry_value(regval_ctr_specific_value(regvals, 0));
+ prs_mem_free(&prs_hkpd);
+ }
+ else
+ {
+ DEBUG(3,("Unsupported key name [%s] for HKPD.\n", name));
+ return WERR_BADFILE;
+ }
+ }
+ /* HKPT calls can be handled out of reg_dynamic.c with the hkpt_params handler */
+ else
{
+ for ( i=0; fetch_reg_values_specific(regkey, &val, i); i++ )
+ {
DEBUG(10,("_reg_info: Testing value [%s]\n", val->valuename));
if ( strequal( val->valuename, name ) ) {
DEBUG(10,("_reg_info: Found match for value [%s]\n", name));
@@ -472,6 +419,7 @@ WERROR _reg_query_value(pipes_struct *p, REG_Q_QUERY_VALUE *q_u, REG_R_QUERY_VAL
}
free_registry_value( val );
+ }
}
init_reg_r_query_value(q_u->ptr_buf, r_u, val, status);
@@ -482,7 +430,6 @@ WERROR _reg_query_value(pipes_struct *p, REG_Q_QUERY_VALUE *q_u, REG_R_QUERY_VAL
return status;
}
-
/*****************************************************************************
Implementation of REG_QUERY_KEY
****************************************************************************/
@@ -998,7 +945,7 @@ static WERROR make_default_reg_sd( TALLOC_CTX *ctx, SEC_DESC **psd )
SEC_ACE ace[2]; /* at most 2 entries */
SEC_ACCESS mask;
SEC_ACL *psa = NULL;
- uint32 sd_size;
+ size_t sd_size;
/* set the owner to BUILTIN\Administrator */
@@ -1092,7 +1039,7 @@ WERROR _reg_save_key(pipes_struct *p, REG_Q_SAVE_KEY *q_u, REG_R_SAVE_KEY *r_u)
WERROR _reg_create_key_ex(pipes_struct *p, REG_Q_CREATE_KEY_EX *q_u, REG_R_CREATE_KEY_EX *r_u)
{
REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->handle);
- REGISTRY_KEY *newparent;
+ REGISTRY_KEY *newparentinfo, *keyinfo;
POLICY_HND newparent_handle;
REGSUBKEY_CTR *subkeys;
BOOL write_result;
@@ -1109,7 +1056,6 @@ WERROR _reg_create_key_ex(pipes_struct *p, REG_Q_CREATE_KEY_EX *q_u, REG_R_CREAT
if ( strrchr( name, '\\' ) ) {
pstring newkeyname;
char *ptr;
- uint32 access_granted;
/* (1) check for enumerate rights on the parent handle. CLients can try
create things like 'SOFTWARE\Samba' on the HKLM handle.
@@ -1122,19 +1068,11 @@ WERROR _reg_create_key_ex(pipes_struct *p, REG_Q_CREATE_KEY_EX *q_u, REG_R_CREAT
ptr = strrchr( newkeyname, '\\' );
*ptr = '\0';
- result = open_registry_key( p, &newparent_handle, parent, newkeyname, 0 );
+ result = open_registry_key( p, &newparent_handle, &newparentinfo,
+ parent, newkeyname, (REG_KEY_READ|REG_KEY_WRITE) );
+
if ( !W_ERROR_IS_OK(result) )
return result;
-
- newparent = find_regkey_index_by_hnd(p, &newparent_handle);
- SMB_ASSERT( newparent != NULL );
-
- if ( !regkey_access_check( newparent, REG_KEY_READ|REG_KEY_WRITE, &access_granted, p->pipe_user.nt_user_token ) ) {
- result = WERR_ACCESS_DENIED;
- goto done;
- }
-
- newparent->access_granted = access_granted;
/* copy the new key name (just the lower most keyname) */
@@ -1142,13 +1080,13 @@ WERROR _reg_create_key_ex(pipes_struct *p, REG_Q_CREATE_KEY_EX *q_u, REG_R_CREAT
}
else {
/* use the existing open key information */
- newparent = parent;
+ newparentinfo = parent;
memcpy( &newparent_handle, &q_u->handle, sizeof(POLICY_HND) );
}
/* (3) check for create subkey rights on the correct parent */
- if ( !(newparent->access_granted & SEC_RIGHTS_CREATE_SUBKEY) ) {
+ if ( !(newparentinfo->access_granted & SEC_RIGHTS_CREATE_SUBKEY) ) {
result = WERR_ACCESS_DENIED;
goto done;
}
@@ -1160,12 +1098,12 @@ WERROR _reg_create_key_ex(pipes_struct *p, REG_Q_CREATE_KEY_EX *q_u, REG_R_CREAT
/* (4) lookup the current keys and add the new one */
- fetch_reg_keys( newparent, subkeys );
+ fetch_reg_keys( newparentinfo, subkeys );
regsubkey_ctr_addkey( subkeys, name );
/* now write to the registry backend */
- write_result = store_reg_keys( newparent, subkeys );
+ write_result = store_reg_keys( newparentinfo, subkeys );
TALLOC_FREE( subkeys );
@@ -1173,16 +1111,15 @@ WERROR _reg_create_key_ex(pipes_struct *p, REG_Q_CREATE_KEY_EX *q_u, REG_R_CREAT
return WERR_REG_IO_FAILURE;
/* (5) open the new key and return the handle. Note that it is probably
- not correct to grant full access on this open handle. We should pass
- the new open through the regkey_access_check() like we do for
- _reg_open_entry() but this is ok for now. */
+ not correct to grant full access on this open handle. */
- result = open_registry_key( p, &r_u->handle, newparent, name, REG_KEY_ALL );
+ result = open_registry_key( p, &r_u->handle, &keyinfo, newparentinfo, name, REG_KEY_READ );
+ keyinfo->access_granted = REG_KEY_ALL;
done:
/* close any intermediate key handles */
- if ( newparent != parent )
+ if ( newparentinfo != parent )
close_registry_key( p, &newparent_handle );
return result;
@@ -1243,7 +1180,7 @@ WERROR _reg_set_value(pipes_struct *p, REG_Q_SET_VALUE *q_u, REG_R_SET_VALUE *r
WERROR _reg_delete_key(pipes_struct *p, REG_Q_DELETE_KEY *q_u, REG_R_DELETE_KEY *r_u)
{
REGISTRY_KEY *parent = find_regkey_index_by_hnd(p, &q_u->handle);
- REGISTRY_KEY *newparent;
+ REGISTRY_KEY *newparentinfo;
POLICY_HND newparent_handle;
REGSUBKEY_CTR *subkeys;
BOOL write_result;
@@ -1252,6 +1189,15 @@ WERROR _reg_delete_key(pipes_struct *p, REG_Q_DELETE_KEY *q_u, REG_R_DELETE_KEY
if ( !parent )
return WERR_BADFID;
+
+ /* MSDN says parent the handle must have been opened with DELETE access */
+
+ /* (1) check for delete rights on the parent */
+
+ if ( !(parent->access_granted & STD_RIGHT_DELETE_ACCESS) ) {
+ result = WERR_ACCESS_DENIED;
+ goto done;
+ }
rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 );
@@ -1260,50 +1206,24 @@ WERROR _reg_delete_key(pipes_struct *p, REG_Q_DELETE_KEY *q_u, REG_R_DELETE_KEY
if ( strrchr( name, '\\' ) ) {
pstring newkeyname;
char *ptr;
- uint32 access_granted;
- /* (1) check for enumerate rights on the parent handle. CLients can try
- create things like 'SOFTWARE\Samba' on the HKLM handle.
- (2) open the path to the child parent key if necessary */
+ /* (2) open the path to the child parent key if necessary */
+ /* split the registry path and save the subkeyname */
- if ( !(parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) )
- return WERR_ACCESS_DENIED;
-
pstrcpy( newkeyname, name );
ptr = strrchr( newkeyname, '\\' );
*ptr = '\0';
+ pstrcpy( name, ptr+1 );
- result = open_registry_key( p, &newparent_handle, parent, newkeyname, 0 );
+ result = open_registry_key( p, &newparent_handle, &newparentinfo, parent, newkeyname, (REG_KEY_READ|REG_KEY_WRITE) );
if ( !W_ERROR_IS_OK(result) )
return result;
-
- newparent = find_regkey_index_by_hnd(p, &newparent_handle);
- SMB_ASSERT( newparent != NULL );
-
- if ( !regkey_access_check( newparent, REG_KEY_READ|REG_KEY_WRITE, &access_granted, p->pipe_user.nt_user_token ) ) {
- result = WERR_ACCESS_DENIED;
- goto done;
- }
-
- newparent->access_granted = access_granted;
-
- /* copy the new key name (just the lower most keyname) */
-
- pstrcpy( name, ptr+1 );
}
else {
/* use the existing open key information */
- newparent = parent;
- memcpy( &newparent_handle, &q_u->handle, sizeof(POLICY_HND) );
+ newparentinfo = parent;
}
- /* (3) check for create subkey rights on the correct parent */
-
- if ( !(newparent->access_granted & STD_RIGHT_DELETE_ACCESS) ) {
- result = WERR_ACCESS_DENIED;
- goto done;
- }
-
if ( !(subkeys = TALLOC_ZERO_P( p->mem_ctx, REGSUBKEY_CTR )) ) {
result = WERR_NOMEM;
goto done;
@@ -1311,13 +1231,13 @@ WERROR _reg_delete_key(pipes_struct *p, REG_Q_DELETE_KEY *q_u, REG_R_DELETE_KEY
/* lookup the current keys and delete the new one */
- fetch_reg_keys( newparent, subkeys );
+ fetch_reg_keys( newparentinfo, subkeys );
regsubkey_ctr_delkey( subkeys, name );
/* now write to the registry backend */
- write_result = store_reg_keys( newparent, subkeys );
+ write_result = store_reg_keys( newparentinfo, subkeys );
TALLOC_FREE( subkeys );
@@ -1326,7 +1246,7 @@ WERROR _reg_delete_key(pipes_struct *p, REG_Q_DELETE_KEY *q_u, REG_R_DELETE_KEY
done:
/* close any intermediate key handles */
- if ( newparent != parent )
+ if ( newparentinfo != parent )
close_registry_key( p, &newparent_handle );
return result;
@@ -1414,5 +1334,3 @@ WERROR _reg_set_key_sec(pipes_struct *p, REG_Q_SET_KEY_SEC *q_u, REG_R_SET_KEY_
return WERR_ACCESS_DENIED;
}
-
-
diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c
index 656241a73f9..b69f03a3a28 100644
--- a/source3/rpc_server/srv_samr_nt.c
+++ b/source3/rpc_server/srv_samr_nt.c
@@ -6,7 +6,7 @@
* Copyright (C) Paul Ashton 1997,
* Copyright (C) Marc Jacobsen 1999,
* Copyright (C) Jeremy Allison 2001-2002,
- * Copyright (C) Jean François Micouleau 1998-2001,
+ * Copyright (C) Jean François Micouleau 1998-2001,
* Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002,
* Copyright (C) Gerald (Jerry) Carter 2003-2004,
* Copyright (C) Simo Sorce 2003.
@@ -88,17 +88,17 @@ static NTSTATUS make_samr_object_sd( TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd
SEC_ACL *psa = NULL;
/* basic access for Everyone */
-
+
init_sec_access(&mask, map->generic_execute | map->generic_read );
init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-
+
/* add Full Access 'BUILTIN\Administrators' and 'BUILTIN\Account Operators */
-
+
init_sec_access(&mask, map->generic_all);
init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
init_sec_ace(&ace[i++], &global_sid_Builtin_Account_Operators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-
+
/* Add Full Access for Domain Admins if we are a DC */
if ( IS_DC ) {
@@ -108,14 +108,14 @@ static NTSTATUS make_samr_object_sd( TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd
}
/* if we have a sid, give it some special access */
-
+
if ( sid ) {
init_sec_access( &mask, sid_access );
init_sec_ace(&ace[i++], sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
- }
-
+}
+
/* create the security descriptor */
-
+
if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) == NULL)
return NT_STATUS_NO_MEMORY;
@@ -347,7 +347,7 @@ NTSTATUS _samr_open_domain(pipes_struct *p, SAMR_Q_OPEN_DOMAIN *q_u, SAMR_R_OPEN
uint32 acc_granted;
uint32 des_access = q_u->flags;
NTSTATUS status;
- size_t sd_size;
+ size_t sd_size;
SE_PRIV se_rights;
r_u->status = NT_STATUS_OK;
@@ -421,7 +421,6 @@ NTSTATUS _samr_get_usrdom_pwinfo(pipes_struct *p, SAMR_Q_GET_USRDOM_PWINFO *q_u,
return r_u->status;
}
-
/*******************************************************************
_samr_set_sec_obj
********************************************************************/
@@ -1456,11 +1455,13 @@ static NTSTATUS get_user_info_18(pipes_struct *p, TALLOC_CTX *mem_ctx, SAM_USER_
BOOL ret;
NTSTATUS nt_status;
- if (!p->ntlmssp_auth_validated)
+ if (p->auth.auth_type != PIPE_AUTH_TYPE_NTLMSSP || p->auth.auth_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
return NT_STATUS_ACCESS_DENIED;
+ }
- if (!(p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) || !(p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SEAL))
+ if (p->auth.auth_level != PIPE_AUTH_LEVEL_PRIVACY) {
return NT_STATUS_ACCESS_DENIED;
+ }
/*
* Do *NOT* do become_root()/unbecome_root() here ! JRA.
@@ -1794,11 +1795,12 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA
time_t u_lock_duration, u_reset_time;
NTTIME nt_lock_duration, nt_reset_time;
uint32 lockout;
-
time_t u_logout;
NTTIME nt_logout;
uint32 account_policy_temp;
+
+ time_t seq_num;
uint32 server_role;
uint32 num_users=0, num_groups=0, num_aliases=0;
@@ -1819,19 +1821,19 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA
switch (q_u->switch_value) {
case 0x01:
- account_policy_get(AP_MIN_PASSWORD_LEN, &account_policy_temp);
+ pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp);
min_pass_len = account_policy_temp;
- account_policy_get(AP_PASSWORD_HISTORY, &account_policy_temp);
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp);
pass_hist = account_policy_temp;
- account_policy_get(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp);
+ pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp);
flag = account_policy_temp;
- account_policy_get(AP_MAX_PASSWORD_AGE, &account_policy_temp);
+ pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp);
u_expire = account_policy_temp;
- account_policy_get(AP_MIN_PASSWORD_AGE, &account_policy_temp);
+ pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp);
u_min_age = account_policy_temp;
unix_to_nt_time_abs(&nt_expire, u_expire);
@@ -1847,21 +1849,23 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA
num_groups=count_sam_groups(&info->disp_info);
unbecome_root();
- account_policy_get(AP_TIME_TO_LOGOUT, &account_policy_temp);
+ pdb_get_account_policy(AP_TIME_TO_LOGOUT, &account_policy_temp);
u_logout = account_policy_temp;
unix_to_nt_time_abs(&nt_logout, u_logout);
+ if (!pdb_get_seq_num(&seq_num))
+ seq_num = time(NULL);
+
server_role = ROLE_DOMAIN_PDC;
if (lp_server_role() == ROLE_DOMAIN_BDC)
server_role = ROLE_DOMAIN_BDC;
- /* The time call below is to get a sequence number for the sam. FIXME !!! JRA. */
- init_unk_info2(&ctr->info.inf2, lp_serverstring(), lp_workgroup(), global_myname(), time(NULL),
+ init_unk_info2(&ctr->info.inf2, lp_serverstring(), lp_workgroup(), global_myname(), seq_num,
num_users, num_groups, num_aliases, nt_logout, server_role);
break;
case 0x03:
- account_policy_get(AP_TIME_TO_LOGOUT, (unsigned int *)&u_logout);
+ pdb_get_account_policy(AP_TIME_TO_LOGOUT, (unsigned int *)&u_logout);
unix_to_nt_time_abs(&nt_logout, u_logout);
init_unk_info3(&ctr->info.inf3, nt_logout);
@@ -1880,18 +1884,21 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA
init_unk_info7(&ctr->info.inf7, server_role);
break;
case 0x08:
- init_unk_info8(&ctr->info.inf8, (uint32) time(NULL));
+ if (!pdb_get_seq_num(&seq_num))
+ seq_num = time(NULL);
+
+ init_unk_info8(&ctr->info.inf8, (uint32) seq_num);
break;
case 0x0c:
- account_policy_get(AP_LOCK_ACCOUNT_DURATION, &account_policy_temp);
+ pdb_get_account_policy(AP_LOCK_ACCOUNT_DURATION, &account_policy_temp);
u_lock_duration = account_policy_temp;
if (u_lock_duration != -1)
u_lock_duration *= 60;
- account_policy_get(AP_RESET_COUNT_TIME, &account_policy_temp);
+ pdb_get_account_policy(AP_RESET_COUNT_TIME, &account_policy_temp);
u_reset_time = account_policy_temp * 60;
- account_policy_get(AP_BAD_ATTEMPT_LOCKOUT, &account_policy_temp);
+ pdb_get_account_policy(AP_BAD_ATTEMPT_LOCKOUT, &account_policy_temp);
lockout = account_policy_temp;
unix_to_nt_time_abs(&nt_lock_duration, u_lock_duration);
@@ -1955,7 +1962,7 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA
rpcstr_pull(account, user_account.buffer, sizeof(account), user_account.uni_str_len*2, 0);
strlower_m(account);
-
+
pdb_init_sam(&sam_pass);
become_root();
@@ -1968,7 +1975,7 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA
}
pdb_free_sam(&sam_pass);
-
+
/*********************************************************************
* HEADS UP! If we have to create a new user account, we have to get
* a new RID from somewhere. This used to be done by the passdb
@@ -1979,7 +1986,7 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA
* of what ever passdb backend people may use.
* --jerry (2003-07-10)
*********************************************************************/
-
+
pw = Get_Pwnam(account);
/* determine which user right we need to check based on the acb_info */
@@ -2005,27 +2012,27 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA
/* only Domain Admins can add a BDC or domain trust */
se_priv_copy( &se_rights, &se_priv_none );
can_add_account = nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS );
- }
}
-
+ }
+
DEBUG(5, ("_samr_create_user: %s can add this account : %s\n",
p->pipe_user_name, can_add_account ? "True":"False" ));
/********** BEGIN Admin BLOCK **********/
-
+
if ( can_add_account )
become_root();
-
+
if ( !pw ) {
if (*add_script) {
- int add_ret;
-
- all_string_sub(add_script, "%u", account, sizeof(add_script));
- add_ret = smbrun(add_script,NULL);
- DEBUG(add_ret ? 0 : 3,("_samr_create_user: Running the command `%s' gave %d\n", add_script, add_ret));
- }
+ int add_ret;
+
+ all_string_sub(add_script, "%u", account, sizeof(add_script));
+ add_ret = smbrun(add_script,NULL);
+ DEBUG(add_ret ? 0 : 3,("_samr_create_user: Running the command `%s' gave %d\n", add_script, add_ret));
+ }
}
-
+
/* implicit call to getpwnam() next. we have a valid SID coming out of this call */
flush_pwnam_cache();
@@ -2147,7 +2154,7 @@ NTSTATUS _samr_connect(pipes_struct *p, SAMR_Q_CONNECT *q_u, SAMR_R_CONNECT *r_u
uint32 acc_granted;
uint32 des_access = q_u->access_mask;
NTSTATUS nt_status;
- size_t sd_size;
+ size_t sd_size;
DEBUG(5,("_samr_connect: %d\n", __LINE__));
@@ -2198,7 +2205,7 @@ NTSTATUS _samr_connect4(pipes_struct *p, SAMR_Q_CONNECT4 *q_u, SAMR_R_CONNECT4 *
uint32 acc_granted;
uint32 des_access = q_u->access_mask;
NTSTATUS nt_status;
- size_t sd_size;
+ size_t sd_size;
DEBUG(5,("_samr_connect4: %d\n", __LINE__));
@@ -2734,7 +2741,7 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE
if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, acc_required, "_samr_set_userinfo"))) {
return r_u->status;
}
-
+
DEBUG(5, ("_samr_set_userinfo: sid:%s, level:%d\n", sid_string_static(&sid), switch_value));
if (ctr == NULL) {
@@ -2765,7 +2772,7 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE
if ( lp_enable_privileges() )
has_enough_rights = nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS );
}
-
+
DEBUG(5, ("_samr_set_userinfo: %s does%s possess sufficient rights\n",
p->pipe_user_name, has_enough_rights ? "" : " not"));
@@ -2905,7 +2912,7 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_
if ( lp_enable_privileges() )
has_enough_rights = nt_token_check_domain_rid( p->pipe_user.nt_user_token, DOMAIN_GROUP_RID_ADMINS );
}
-
+
DEBUG(5, ("_samr_set_userinfo: %s does%s possess sufficient rights\n",
p->pipe_user_name, has_enough_rights ? "" : " not"));
@@ -3597,7 +3604,7 @@ NTSTATUS _samr_delete_dom_group(pipes_struct *p, SAMR_Q_DELETE_DOM_GROUP *q_u, S
gid=map.gid;
/* check if group really exists */
- if ( (grp=getgrgid(gid)) == NULL)
+ if ( (grp=getgrgid(gid)) == NULL)
return NT_STATUS_NO_SUCH_GROUP;
se_priv_copy( &se_rights, &se_add_users );
@@ -4195,6 +4202,8 @@ NTSTATUS _samr_unknown_2e(pipes_struct *p, SAMR_Q_UNKNOWN_2E *q_u, SAMR_R_UNKNOW
uint32 num_users=0, num_groups=0, num_aliases=0;
uint32 account_policy_temp;
+
+ time_t seq_num;
uint32 server_role;
if ((ctr = TALLOC_ZERO_P(p->mem_ctx, SAM_UNK_CTR)) == NULL)
@@ -4212,19 +4221,19 @@ NTSTATUS _samr_unknown_2e(pipes_struct *p, SAMR_Q_UNKNOWN_2E *q_u, SAMR_R_UNKNOW
switch (q_u->switch_value) {
case 0x01:
- account_policy_get(AP_MIN_PASSWORD_LEN, &account_policy_temp);
+ pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp);
min_pass_len = account_policy_temp;
- account_policy_get(AP_PASSWORD_HISTORY, &account_policy_temp);
+ pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp);
pass_hist = account_policy_temp;
- account_policy_get(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp);
+ pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp);
flag = account_policy_temp;
- account_policy_get(AP_MAX_PASSWORD_AGE, &account_policy_temp);
+ pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp);
u_expire = account_policy_temp;
- account_policy_get(AP_MIN_PASSWORD_AGE, &account_policy_temp);
+ pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp);
u_min_age = account_policy_temp;
unix_to_nt_time_abs(&nt_expire, u_expire);
@@ -4242,21 +4251,23 @@ NTSTATUS _samr_unknown_2e(pipes_struct *p, SAMR_Q_UNKNOWN_2E *q_u, SAMR_R_UNKNOW
free_samr_db(info);
- account_policy_get(AP_TIME_TO_LOGOUT, &account_policy_temp);
+ pdb_get_account_policy(AP_TIME_TO_LOGOUT, &account_policy_temp);
u_logout = account_policy_temp;
unix_to_nt_time_abs(&nt_logout, u_logout);
+ if (!pdb_get_seq_num(&seq_num))
+ seq_num = time(NULL);
+
server_role = ROLE_DOMAIN_PDC;
if (lp_server_role() == ROLE_DOMAIN_BDC)
server_role = ROLE_DOMAIN_BDC;
- /* The time call below is to get a sequence number for the sam. FIXME !!! JRA. */
- init_unk_info2(&ctr->info.inf2, lp_serverstring(), lp_workgroup(), global_myname(), time(NULL),
+ init_unk_info2(&ctr->info.inf2, lp_serverstring(), lp_workgroup(), global_myname(), seq_num,
num_users, num_groups, num_aliases, nt_logout, server_role);
break;
case 0x03:
- account_policy_get(AP_TIME_TO_LOGOUT, &account_policy_temp);
+ pdb_get_account_policy(AP_TIME_TO_LOGOUT, &account_policy_temp);
u_logout = account_policy_temp;
unix_to_nt_time_abs(&nt_logout, u_logout);
@@ -4273,21 +4284,25 @@ NTSTATUS _samr_unknown_2e(pipes_struct *p, SAMR_Q_UNKNOWN_2E *q_u, SAMR_R_UNKNOW
server_role = ROLE_DOMAIN_PDC;
if (lp_server_role() == ROLE_DOMAIN_BDC)
server_role = ROLE_DOMAIN_BDC;
+
init_unk_info7(&ctr->info.inf7, server_role);
break;
case 0x08:
- init_unk_info8(&ctr->info.inf8, (uint32) time(NULL));
+ if (!pdb_get_seq_num(&seq_num))
+ seq_num = time(NULL);
+
+ init_unk_info8(&ctr->info.inf8, (uint32) seq_num);
break;
case 0x0c:
- account_policy_get(AP_LOCK_ACCOUNT_DURATION, &account_policy_temp);
+ pdb_get_account_policy(AP_LOCK_ACCOUNT_DURATION, &account_policy_temp);
u_lock_duration = account_policy_temp;
if (u_lock_duration != -1)
u_lock_duration *= 60;
- account_policy_get(AP_RESET_COUNT_TIME, &account_policy_temp);
+ pdb_get_account_policy(AP_RESET_COUNT_TIME, &account_policy_temp);
u_reset_time = account_policy_temp * 60;
- account_policy_get(AP_BAD_ATTEMPT_LOCKOUT, &account_policy_temp);
+ pdb_get_account_policy(AP_BAD_ATTEMPT_LOCKOUT, &account_policy_temp);
lockout = account_policy_temp;
unix_to_nt_time_abs(&nt_lock_duration, u_lock_duration);
@@ -4331,17 +4346,17 @@ NTSTATUS _samr_set_dom_info(pipes_struct *p, SAMR_Q_SET_DOMAIN_INFO *q_u, SAMR_R
u_expire=nt_time_to_unix_abs(&q_u->ctr->info.inf1.expire);
u_min_age=nt_time_to_unix_abs(&q_u->ctr->info.inf1.min_passwordage);
- account_policy_set(AP_MIN_PASSWORD_LEN, (uint32)q_u->ctr->info.inf1.min_length_password);
- account_policy_set(AP_PASSWORD_HISTORY, (uint32)q_u->ctr->info.inf1.password_history);
- account_policy_set(AP_USER_MUST_LOGON_TO_CHG_PASS, (uint32)q_u->ctr->info.inf1.flag);
- account_policy_set(AP_MAX_PASSWORD_AGE, (int)u_expire);
- account_policy_set(AP_MIN_PASSWORD_AGE, (int)u_min_age);
+ pdb_set_account_policy(AP_MIN_PASSWORD_LEN, (uint32)q_u->ctr->info.inf1.min_length_password);
+ pdb_set_account_policy(AP_PASSWORD_HISTORY, (uint32)q_u->ctr->info.inf1.password_history);
+ pdb_set_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, (uint32)q_u->ctr->info.inf1.flag);
+ pdb_set_account_policy(AP_MAX_PASSWORD_AGE, (int)u_expire);
+ pdb_set_account_policy(AP_MIN_PASSWORD_AGE, (int)u_min_age);
break;
case 0x02:
break;
case 0x03:
u_logout=nt_time_to_unix_abs(&q_u->ctr->info.inf3.logout);
- account_policy_set(AP_TIME_TO_LOGOUT, (int)u_logout);
+ pdb_set_account_policy(AP_TIME_TO_LOGOUT, (int)u_logout);
break;
case 0x05:
break;
@@ -4356,9 +4371,9 @@ NTSTATUS _samr_set_dom_info(pipes_struct *p, SAMR_Q_SET_DOMAIN_INFO *q_u, SAMR_R
u_reset_time=nt_time_to_unix_abs(&q_u->ctr->info.inf12.reset_count)/60;
- account_policy_set(AP_LOCK_ACCOUNT_DURATION, (int)u_lock_duration);
- account_policy_set(AP_RESET_COUNT_TIME, (int)u_reset_time);
- account_policy_set(AP_BAD_ATTEMPT_LOCKOUT, (uint32)q_u->ctr->info.inf12.bad_attempt_lockout);
+ pdb_set_account_policy(AP_LOCK_ACCOUNT_DURATION, (int)u_lock_duration);
+ pdb_set_account_policy(AP_RESET_COUNT_TIME, (int)u_reset_time);
+ pdb_set_account_policy(AP_BAD_ATTEMPT_LOCKOUT, (uint32)q_u->ctr->info.inf12.bad_attempt_lockout);
break;
default:
return NT_STATUS_INVALID_INFO_CLASS;
diff --git a/source3/rpc_server/srv_samr_util.c b/source3/rpc_server/srv_samr_util.c
index 24869d5d2bd..1d9a8ecd1db 100644
--- a/source3/rpc_server/srv_samr_util.c
+++ b/source3/rpc_server/srv_samr_util.c
@@ -291,7 +291,7 @@ void copy_id21_to_sam_passwd(SAM_ACCOUNT *to, SAM_USER_INFO_21 *from)
uint32 expire;
time_t new_time;
if (pdb_get_pass_must_change_time(to) == 0) {
- if (!account_policy_get(AP_MAX_PASSWORD_AGE, &expire)
+ if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &expire)
|| expire == (uint32)-1) {
new_time = get_time_t_max();
} else {
@@ -531,7 +531,7 @@ void copy_id23_to_sam_passwd(SAM_ACCOUNT *to, SAM_USER_INFO_23 *from)
uint32 expire;
time_t new_time;
if (pdb_get_pass_must_change_time(to) == 0) {
- if (!account_policy_get(AP_MAX_PASSWORD_AGE, &expire)
+ if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &expire)
|| expire == (uint32)-1) {
new_time = get_time_t_max();
} else {
diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c
index cda3f26137c..5233d6c252d 100644
--- a/source3/rpc_server/srv_spoolss_nt.c
+++ b/source3/rpc_server/srv_spoolss_nt.c
@@ -75,7 +75,7 @@ typedef struct _counter_printer_0 {
static counter_printer_0 *counter_list;
-static struct cli_state notify_cli; /* print notify back-channel */
+static struct rpc_pipe_client *notify_cli_pipe; /* print notify back-channel pipe handle*/
static uint32 smb_connections=0;
@@ -166,7 +166,7 @@ static void srv_spoolss_replycloseprinter(int snum, POLICY_HND *handle)
return;
}
- result = cli_spoolss_reply_close_printer(&notify_cli, notify_cli.mem_ctx, handle);
+ result = rpccli_spoolss_reply_close_printer(notify_cli_pipe, notify_cli_pipe->cli->mem_ctx, handle);
if (!W_ERROR_IS_OK(result))
DEBUG(0,("srv_spoolss_replycloseprinter: reply_close_printer failed [%s].\n",
@@ -174,9 +174,8 @@ static void srv_spoolss_replycloseprinter(int snum, POLICY_HND *handle)
/* if it's the last connection, deconnect the IPC$ share */
if (smb_connections==1) {
- cli_nt_session_close(&notify_cli);
- cli_ulogoff(&notify_cli);
- cli_shutdown(&notify_cli);
+ cli_shutdown(notify_cli_pipe->cli);
+ notify_cli_pipe = NULL; /* The above call shuts downn the pipe also. */
message_deregister(MSG_PRINTER_NOTIFY2);
/* Tell the connections db we're no longer interested in
@@ -688,7 +687,7 @@ static void notify_system_time(struct spoolss_notify_msg *msg,
return;
}
- if (!prs_init(&ps, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL)) {
+ if (!prs_init(&ps, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL)) {
DEBUG(5, ("notify_system_time: prs_init() failed\n"));
return;
}
@@ -1021,7 +1020,7 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
}
if ( sending_msg_count ) {
- cli_spoolss_rrpcn( &notify_cli, mem_ctx, &p->notify.client_hnd,
+ rpccli_spoolss_rrpcn( notify_cli_pipe, mem_ctx, &p->notify.client_hnd,
data_len, data, p->notify.change, 0 );
}
}
@@ -1075,7 +1074,8 @@ static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, struct timeval *tv, voi
Receive a notify2 message list
********************************************************************/
-static void receive_notify2_message_list(int msg_type, pid_t src, void *msg, size_t len)
+static void receive_notify2_message_list(int msg_type, struct process_id src,
+ void *msg, size_t len)
{
size_t msg_count, i;
char *buf = (char *)msg;
@@ -1176,7 +1176,8 @@ static BOOL srv_spoolss_drv_upgrade_printer(char* drivername)
DEBUG(10,("srv_spoolss_drv_upgrade_printer: Sending message about driver upgrade [%s]\n",
drivername));
- message_send_pid(sys_getpid(), MSG_PRINTER_DRVUPGRADE, drivername, len+1, False);
+ message_send_pid(pid_to_procid(sys_getpid()),
+ MSG_PRINTER_DRVUPGRADE, drivername, len+1, False);
return True;
}
@@ -1186,7 +1187,7 @@ static BOOL srv_spoolss_drv_upgrade_printer(char* drivername)
over all printers, upgrading ones as necessary
**********************************************************************/
-void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
+void do_drv_upgrade_printer(int msg_type, struct process_id src, void *buf, size_t len)
{
fstring drivername;
int snum;
@@ -1272,7 +1273,8 @@ static BOOL srv_spoolss_reset_printerdata(char* drivername)
DEBUG(10,("srv_spoolss_reset_printerdata: Sending message about resetting printerdata [%s]\n",
drivername));
- message_send_pid(sys_getpid(), MSG_PRINTERDATA_INIT_RESET, drivername, len+1, False);
+ message_send_pid(pid_to_procid(sys_getpid()),
+ MSG_PRINTERDATA_INIT_RESET, drivername, len+1, False);
return True;
}
@@ -1282,7 +1284,8 @@ static BOOL srv_spoolss_reset_printerdata(char* drivername)
over all printers, resetting printer data as neessary
**********************************************************************/
-void reset_all_printerdata(int msg_type, pid_t src, void *buf, size_t len)
+void reset_all_printerdata(int msg_type, struct process_id src,
+ void *buf, size_t len)
{
fstring drivername;
int snum;
@@ -2001,7 +2004,10 @@ WERROR _spoolss_deleteprinterdriver(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIVER
/* this should not have failed---if it did, report to client */
if ( !W_ERROR_IS_OK(status_win2k) )
+ {
+ status = status_win2k;
goto done;
+ }
}
}
@@ -2479,9 +2485,10 @@ done:
Connect to the client machine.
**********************************************************/
-static BOOL spoolss_connect_to_client(struct cli_state *the_cli,
+static BOOL spoolss_connect_to_client(struct cli_state *the_cli, struct rpc_pipe_client **pp_pipe,
struct in_addr *client_ip, const char *remote_machine)
{
+ NTSTATUS ret;
ZERO_STRUCTP(the_cli);
if(cli_initialise(the_cli) == NULL) {
@@ -2563,10 +2570,10 @@ static BOOL spoolss_connect_to_client(struct cli_state *the_cli,
* Now start the NT Domain stuff :-).
*/
- if(cli_nt_session_open(the_cli, PI_SPOOLSS) == False) {
- DEBUG(0,("spoolss_connect_to_client: unable to open the domain client session to machine %s. Error was : %s.\n", remote_machine, cli_errstr(the_cli)));
- cli_nt_session_close(the_cli);
- cli_ulogoff(the_cli);
+ *pp_pipe = cli_rpc_pipe_open_noauth(the_cli, PI_SPOOLSS, &ret);
+ if(!*pp_pipe) {
+ DEBUG(0,("spoolss_connect_to_client: unable to open the spoolss pipe on machine %s. Error was : %s.\n",
+ remote_machine, nt_errstr(ret)));
cli_shutdown(the_cli);
return False;
}
@@ -2589,13 +2596,14 @@ static BOOL srv_spoolss_replyopenprinter(int snum, const char *printer,
* and connect to the IPC$ share anonymously
*/
if (smb_connections==0) {
+ struct cli_state notify_cli; /* print notify back-channel */
fstring unix_printer;
fstrcpy(unix_printer, printer+2); /* the +2 is to strip the leading 2 backslashs */
ZERO_STRUCT(notify_cli);
- if(!spoolss_connect_to_client(&notify_cli, client_ip, unix_printer))
+ if(!spoolss_connect_to_client(&notify_cli, &notify_cli_pipe, client_ip, unix_printer))
return False;
message_register(MSG_PRINTER_NOTIFY2, receive_notify2_message_list);
@@ -2614,7 +2622,7 @@ static BOOL srv_spoolss_replyopenprinter(int snum, const char *printer,
smb_connections++;
- result = cli_spoolss_reply_open_printer(&notify_cli, notify_cli.mem_ctx, printer, localprinter,
+ result = rpccli_spoolss_reply_open_printer(notify_cli_pipe, notify_cli_pipe->cli->mem_ctx, printer, localprinter,
type, handle);
if (!W_ERROR_IS_OK(result))
@@ -6117,17 +6125,12 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
|| !strequal(printer->info_2->portname, old_printer->info_2->portname)
|| !strequal(printer->info_2->location, old_printer->info_2->location)) )
{
+ /* add_printer_hook() will call reload_services() */
+
if ( !add_printer_hook(p->pipe_user.nt_user_token, printer) ) {
result = WERR_ACCESS_DENIED;
goto done;
}
-
- /*
- * make sure we actually reload the services after
- * this as smb.conf could have a new section in it
- * .... shouldn't .... but could
- */
- reload_services(False);
}
/*
diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c
index e9dd015421c..9643b2a7249 100644
--- a/source3/rpc_server/srv_srvsvc_nt.c
+++ b/source3/rpc_server/srv_srvsvc_nt.c
@@ -113,7 +113,8 @@ static void init_srv_share_info_2(pipes_struct *p, SRV_SHARE_INFO_2 *sh2, int sn
What to do when smb.conf is updated.
********************************************************************/
-static void smb_conf_updated(int msg_type, pid_t src, void *buf, size_t len)
+static void smb_conf_updated(int msg_type, struct process_id src,
+ void *buf, size_t len)
{
DEBUG(10,("smb_conf_updated: Got message saying smb.conf was updated. Reloading.\n"));
reload_services(False);
@@ -1394,7 +1395,7 @@ WERROR _srv_net_sess_del(pipes_struct *p, SRV_Q_NET_SESS_DEL *q_u, SRV_R_NET_SES
become_root();
}
- if (message_send_pid(session_list[snum].pid, MSG_SHUTDOWN, NULL, 0, False))
+ if (message_send_pid(pid_to_procid(session_list[snum].pid), MSG_SHUTDOWN, NULL, 0, False))
r_u->status = WERR_OK;
if (not_root)
diff --git a/source3/rpc_server/srv_svcctl.c b/source3/rpc_server/srv_svcctl.c
index 6ba26414d36..31d8bbe9b3d 100644
--- a/source3/rpc_server/srv_svcctl.c
+++ b/source3/rpc_server/srv_svcctl.c
@@ -310,23 +310,75 @@ static BOOL api_svcctl_query_service_config2(pipes_struct *p)
}
/*******************************************************************
+ ********************************************************************/
+
+static BOOL api_svcctl_lock_service_db(pipes_struct *p)
+{
+ SVCCTL_Q_LOCK_SERVICE_DB q_u;
+ SVCCTL_R_LOCK_SERVICE_DB r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!svcctl_io_q_lock_service_db("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _svcctl_lock_service_db(p, &q_u, &r_u);
+
+ if(!svcctl_io_r_lock_service_db("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
+ ********************************************************************/
+
+static BOOL api_svcctl_unlock_service_db(pipes_struct *p)
+{
+ SVCCTL_Q_UNLOCK_SERVICE_DB q_u;
+ SVCCTL_R_UNLOCK_SERVICE_DB r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!svcctl_io_q_unlock_service_db("", &q_u, data, 0))
+ return False;
+
+ r_u.status = _svcctl_unlock_service_db(p, &q_u, &r_u);
+
+ if(!svcctl_io_r_unlock_service_db("", &r_u, rdata, 0))
+ return False;
+
+ return True;
+}
+
+
+/*******************************************************************
\PIPE\svcctl commands
********************************************************************/
static struct api_struct api_svcctl_cmds[] =
{
- { "SVCCTL_CLOSE_SERVICE" , SVCCTL_CLOSE_SERVICE , api_svcctl_close_service },
- { "SVCCTL_OPEN_SCMANAGER_W" , SVCCTL_OPEN_SCMANAGER_W , api_svcctl_open_scmanager },
- { "SVCCTL_OPEN_SERVICE_W" , SVCCTL_OPEN_SERVICE_W , api_svcctl_open_service },
- { "SVCCTL_GET_DISPLAY_NAME" , SVCCTL_GET_DISPLAY_NAME , api_svcctl_get_display_name },
- { "SVCCTL_QUERY_STATUS" , SVCCTL_QUERY_STATUS , api_svcctl_query_status },
- { "SVCCTL_QUERY_SERVICE_CONFIG_W", SVCCTL_QUERY_SERVICE_CONFIG_W, api_svcctl_query_service_config },
- { "SVCCTL_QUERY_SERVICE_CONFIG2_W", SVCCTL_QUERY_SERVICE_CONFIG2_W, api_svcctl_query_service_config2 },
- { "SVCCTL_ENUM_SERVICES_STATUS_W", SVCCTL_ENUM_SERVICES_STATUS_W, api_svcctl_enum_services_status },
- { "SVCCTL_ENUM_DEPENDENT_SERVICES_W", SVCCTL_ENUM_DEPENDENT_SERVICES_W, api_svcctl_enum_dependent_services },
- { "SVCCTL_START_SERVICE_W" , SVCCTL_START_SERVICE_W , api_svcctl_start_service },
- { "SVCCTL_CONTROL_SERVICE" , SVCCTL_CONTROL_SERVICE , api_svcctl_control_service },
- { "SVCCTL_QUERY_SERVICE_STATUSEX_W", SVCCTL_QUERY_SERVICE_STATUSEX_W, api_svcctl_query_service_status_ex }
+ { "SVCCTL_CLOSE_SERVICE" , SVCCTL_CLOSE_SERVICE , api_svcctl_close_service },
+ { "SVCCTL_OPEN_SCMANAGER_W" , SVCCTL_OPEN_SCMANAGER_W , api_svcctl_open_scmanager },
+ { "SVCCTL_OPEN_SERVICE_W" , SVCCTL_OPEN_SERVICE_W , api_svcctl_open_service },
+ { "SVCCTL_GET_DISPLAY_NAME" , SVCCTL_GET_DISPLAY_NAME , api_svcctl_get_display_name },
+ { "SVCCTL_QUERY_STATUS" , SVCCTL_QUERY_STATUS , api_svcctl_query_status },
+ { "SVCCTL_QUERY_SERVICE_CONFIG_W" , SVCCTL_QUERY_SERVICE_CONFIG_W , api_svcctl_query_service_config },
+ { "SVCCTL_QUERY_SERVICE_CONFIG2_W" , SVCCTL_QUERY_SERVICE_CONFIG2_W , api_svcctl_query_service_config2 },
+ { "SVCCTL_ENUM_SERVICES_STATUS_W" , SVCCTL_ENUM_SERVICES_STATUS_W , api_svcctl_enum_services_status },
+ { "SVCCTL_ENUM_DEPENDENT_SERVICES_W" , SVCCTL_ENUM_DEPENDENT_SERVICES_W , api_svcctl_enum_dependent_services },
+ { "SVCCTL_START_SERVICE_W" , SVCCTL_START_SERVICE_W , api_svcctl_start_service },
+ { "SVCCTL_CONTROL_SERVICE" , SVCCTL_CONTROL_SERVICE , api_svcctl_control_service },
+ { "SVCCTL_QUERY_SERVICE_STATUSEX_W" , SVCCTL_QUERY_SERVICE_STATUSEX_W , api_svcctl_query_service_status_ex },
+ { "SVCCTL_LOCK_SERVICE_DB" , SVCCTL_LOCK_SERVICE_DB , api_svcctl_lock_service_db },
+ { "SVCCTL_UNLOCK_SERVICE_DB" , SVCCTL_UNLOCK_SERVICE_DB , api_svcctl_unlock_service_db }
};
diff --git a/source3/rpc_server/srv_svcctl_nt.c b/source3/rpc_server/srv_svcctl_nt.c
index 538b97a2b17..e8df2acb22f 100644
--- a/source3/rpc_server/srv_svcctl_nt.c
+++ b/source3/rpc_server/srv_svcctl_nt.c
@@ -1,8 +1,11 @@
/*
* Unix SMB/CIFS implementation.
* RPC Pipe client / server routines
- * Copyright (C) Gerald (Jerry) Carter 2005,
+ *
* Copyright (C) Marcin Krzysztof Porwit 2005.
+ *
+ * Largely Rewritten (Again) by:
+ * Copyright (C) Gerald (Jerry) Carter 2005.
*
* 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
@@ -19,51 +22,97 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* TODO - Do the OpenService service name matching case-independently, or at least make it an option. */
-
-
#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_SRV
-#define SERVICEDB_VERSION_V1 1 /* Will there be more? */
-#define INTERNAL_SERVICES_LIST "NETLOGON Spooler"
-
-/* */
-/* scripts will execute from the following libdir, if they are in the enable svcctl=<list of scripts> */
-/* these should likely be symbolic links. Note that information about them will be extracted from the files themselves */
-/* using the LSB standard keynames for various information */
-
-#define SVCCTL_SCRIPT_DIR "/svcctl/"
-
-
-struct service_control_op_table {
+struct service_control_op {
const char *name;
SERVICE_CONTROL_OPS *ops;
};
extern SERVICE_CONTROL_OPS spoolss_svc_ops;
+extern SERVICE_CONTROL_OPS rcinit_svc_ops;
+extern SERVICE_CONTROL_OPS netlogon_svc_ops;
+extern SERVICE_CONTROL_OPS winreg_svc_ops;
-struct service_control_op_table svcctl_ops[] = {
- { "Spooler", &spoolss_svc_ops },
- { "NETLOGON", NULL },
- { NULL, NULL }
-};
+struct service_control_op *svcctl_ops;
+
+static struct generic_mapping scm_generic_map =
+ { SC_MANAGER_READ_ACCESS, SC_MANAGER_WRITE_ACCESS, SC_MANAGER_EXECUTE_ACCESS, SC_MANAGER_ALL_ACCESS };
+static struct generic_mapping svc_generic_map =
+ { SERVICE_READ_ACCESS, SERVICE_WRITE_ACCESS, SERVICE_EXECUTE_ACCESS, SERVICE_ALL_ACCESS };
/********************************************************************
********************************************************************/
+BOOL init_service_op_table( void )
+{
+ const char **service_list = lp_svcctl_list();
+ int num_services = 3 + str_list_count( service_list );
+ int i;
+
+ if ( !(svcctl_ops = TALLOC_ARRAY( NULL, struct service_control_op, num_services+1)) ) {
+ DEBUG(0,("init_service_op_table: talloc() failed!\n"));
+ return False;
+ }
+
+ /* services listed in smb.conf get the rc.init interface */
+
+ for ( i=0; service_list[i]; i++ ) {
+ svcctl_ops[i].name = talloc_strdup( svcctl_ops, service_list[i] );
+ svcctl_ops[i].ops = &rcinit_svc_ops;
+ }
+
+ /* add builtin services */
+
+ svcctl_ops[i].name = talloc_strdup( svcctl_ops, "Spooler" );
+ svcctl_ops[i].ops = &spoolss_svc_ops;
+ i++;
+
+ svcctl_ops[i].name = talloc_strdup( svcctl_ops, "NETLOGON" );
+ svcctl_ops[i].ops = &netlogon_svc_ops;
+ i++;
+
+ svcctl_ops[i].name = talloc_strdup( svcctl_ops, "RemoteRegistry" );
+ svcctl_ops[i].ops = &winreg_svc_ops;
+ i++;
+
+ /* NULL terminate the array */
+
+ svcctl_ops[i].name = NULL;
+ svcctl_ops[i].ops = NULL;
+
+ return True;
+}
+
+/********************************************************************
+********************************************************************/
+
+static struct service_control_op* find_service_by_name( const char *name )
+{
+ int i;
+
+ for ( i=0; svcctl_ops[i].name; i++ ) {
+ if ( strequal( name, svcctl_ops[i].name ) )
+ return &svcctl_ops[i];
+ }
+
+ return NULL;
+}
+/********************************************************************
+********************************************************************/
+
static NTSTATUS svcctl_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token,
uint32 access_desired, uint32 *access_granted )
{
NTSTATUS result;
if ( geteuid() == sec_initial_uid() ) {
- DEBUG(5,("svcctl_access_check: access check bypassed for 'root'\n"));
- *access_granted = access_desired;
- return NT_STATUS_OK;
+ DEBUG(5,("svcctl_access_check: using root's token\n"));
+ token = get_root_nt_token();
}
se_access_check( sec_desc, token, access_desired, access_granted, &result );
@@ -81,7 +130,7 @@ static SEC_DESC* construct_scm_sd( TALLOC_CTX *ctx )
size_t i = 0;
SEC_DESC *sd;
SEC_ACL *acl;
- uint32 sd_size;
+ size_t sd_size;
/* basic access for Everyone */
@@ -105,51 +154,13 @@ static SEC_DESC* construct_scm_sd( TALLOC_CTX *ctx )
return sd;
}
-/********************************************************************
-********************************************************************/
-
-static SEC_DESC* construct_service_sd( TALLOC_CTX *ctx )
-{
- SEC_ACE ace[4];
- SEC_ACCESS mask;
- size_t i = 0;
- SEC_DESC *sd;
- SEC_ACL *acl;
- uint32 sd_size;
-
- /* basic access for Everyone */
-
- init_sec_access(&mask, SERVICE_READ_ACCESS );
- init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-
- init_sec_access(&mask,SERVICE_EXECUTE_ACCESS );
- init_sec_ace(&ace[i++], &global_sid_Builtin_Power_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-
- init_sec_access(&mask,SERVICE_ALL_ACCESS );
- init_sec_ace(&ace[i++], &global_sid_Builtin_Server_Operators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
- init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-
- /* create the security descriptor */
-
- if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
- return NULL;
-
- if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
- return NULL;
-
- return sd;
-}
-
/******************************************************************
free() function for REGISTRY_KEY
*****************************************************************/
static void free_service_handle_info(void *ptr)
{
- SERVICE_INFO *info = (SERVICE_INFO*)ptr;
-
- SAFE_FREE(info->name);
- SAFE_FREE(info);
+ TALLOC_FREE( ptr );
}
/******************************************************************
@@ -171,44 +182,50 @@ static SERVICE_INFO *find_service_info_by_hnd(pipes_struct *p, POLICY_HND *hnd)
/******************************************************************
*****************************************************************/
-static WERROR create_open_service_handle( pipes_struct *p, POLICY_HND *handle,
+static WERROR create_open_service_handle( pipes_struct *p, POLICY_HND *handle, uint32 type,
const char *service, uint32 access_granted )
{
SERVICE_INFO *info = NULL;
WERROR result = WERR_OK;
+ struct service_control_op *s_op;
- if ( !(info = SMB_MALLOC_P( SERVICE_INFO )) )
+ if ( !(info = TALLOC_ZERO_P( NULL, SERVICE_INFO )) )
return WERR_NOMEM;
- ZERO_STRUCTP( info );
-
/* the Service Manager has a NULL name */
- if ( !service ) {
+ info->type = SVC_HANDLE_IS_SCM;
+
+ switch ( type ) {
+ case SVC_HANDLE_IS_SCM:
info->type = SVC_HANDLE_IS_SCM;
- } else {
- int i;
+ break;
+ case SVC_HANDLE_IS_DBLOCK:
+ info->type = SVC_HANDLE_IS_DBLOCK;
+ break;
+
+ case SVC_HANDLE_IS_SERVICE:
info->type = SVC_HANDLE_IS_SERVICE;
/* lookup the SERVICE_CONTROL_OPS */
- for ( i=0; svcctl_ops[i].name; i++ ) {
- if ( strequal( svcctl_ops[i].name, service ) ) {
- info->ops = svcctl_ops[i].ops;
- break;
- }
- }
-
- if ( !svcctl_ops[i].name ) {
+ if ( !(s_op = find_service_by_name( service )) ) {
result = WERR_NO_SUCH_SERVICE;
goto done;
}
+
+ info->ops = s_op->ops;
- if ( !(info->name = SMB_STRDUP( service )) ) {
+ if ( !(info->name = talloc_strdup( info, s_op->name )) ) {
result = WERR_NOMEM;
goto done;
}
+ break;
+
+ default:
+ result = WERR_NO_SUCH_SERVICE;
+ goto done;
}
info->access_granted = access_granted;
@@ -241,11 +258,12 @@ WERROR _svcctl_open_scmanager(pipes_struct *p, SVCCTL_Q_OPEN_SCMANAGER *q_u, SVC
if ( !(sec_desc = construct_scm_sd( p->mem_ctx )) )
return WERR_NOMEM;
+ se_map_generic( &q_u->access, &scm_generic_map );
status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
if ( !NT_STATUS_IS_OK(status) )
return ntstatus_to_werror( status );
- return create_open_service_handle( p, &r_u->handle, NULL, access_granted );
+ return create_open_service_handle( p, &r_u->handle, SVC_HANDLE_IS_SCM, NULL, access_granted );
}
/********************************************************************
@@ -268,21 +286,18 @@ WERROR _svcctl_open_service(pipes_struct *p, SVCCTL_Q_OPEN_SERVICE *q_u, SVCCTL_
if ( !find_service_info_by_hnd( p, &q_u->handle ) )
return WERR_BADFID;
- /* perform access checks */
+ /* perform access checks. Use the root token in order to ensure that we
+ retreive the security descriptor */
- if ( !(sec_desc = construct_service_sd( p->mem_ctx )) )
+ if ( !(sec_desc = svcctl_get_secdesc( p->mem_ctx, service, get_root_nt_token() )) )
return WERR_NOMEM;
+ se_map_generic( &q_u->access, &svc_generic_map );
status = svcctl_access_check( sec_desc, p->pipe_user.nt_user_token, q_u->access, &access_granted );
if ( !NT_STATUS_IS_OK(status) )
return ntstatus_to_werror( status );
-
-#if 0 /* FIXME!!! */
- if ( ! get_service_info(service_tdb, service, info) ) {
- return WERR_NO_SUCH_SERVICE;
-#endif
- return create_open_service_handle( p, &r_u->handle, service, access_granted );
+ return create_open_service_handle( p, &r_u->handle, SVC_HANDLE_IS_SERVICE, service, access_granted );
}
/********************************************************************
@@ -299,7 +314,7 @@ WERROR _svcctl_close_service(pipes_struct *p, SVCCTL_Q_CLOSE_SERVICE *q_u, SVCCT
WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u, SVCCTL_R_GET_DISPLAY_NAME *r_u)
{
fstring service;
- fstring displayname;
+ const char *display_name;
SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
/* can only use an SCM handle here */
@@ -308,12 +323,9 @@ WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u,
return WERR_BADFID;
rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
-
- /* need a tdb lookup here or something */
- fstrcpy( displayname, "FIX ME!" );
-
- init_svcctl_r_get_display_name( r_u, displayname );
+ display_name = svcctl_lookup_dispname( service, p->pipe_user.nt_user_token );
+ init_svcctl_r_get_display_name( r_u, display_name );
return WERR_OK;
}
@@ -335,87 +347,40 @@ WERROR _svcctl_query_status(pipes_struct *p, SVCCTL_Q_QUERY_STATUS *q_u, SVCCTL_
/* try the service specific status call */
- if ( info->ops )
- return info->ops->service_status( &r_u->svc_status );
-
- /* default action for now */
-
- r_u->svc_status.type = 0x0020;
- r_u->svc_status.state = 0x0004;
- r_u->svc_status.controls_accepted = 0x0005;
-
- return WERR_OK;
+ return info->ops->service_status( info->name, &r_u->svc_status );
}
+/********************************************************************
+********************************************************************/
-/*********************************************************************
- TODO - for internal services, do similar to external services, except
- we have to call the right status routine...
-**********************************************************************/
-
-static WERROR enum_internal_services(TALLOC_CTX *ctx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services, uint32 *added)
+static int enumerate_status( TALLOC_CTX *ctx, ENUM_SERVICES_STATUS **status, NT_USER_TOKEN *token )
{
- int num_services = 2;
- int i = 0;
- ENUM_SERVICES_STATUS *services=NULL;
-
- if (!svc_ptr || !(*svc_ptr))
- return WERR_NOMEM;
-
- services = *svc_ptr;
-
- if ( (existing_services > 0) && svc_ptr && *svc_ptr ) {
- ENUM_SERVICES_STATUS *tmp_services = NULL;
- uint32 total_svc = existing_services + num_services;
-
- if ( !(tmp_services = TALLOC_REALLOC_ARRAY( ctx, services, ENUM_SERVICES_STATUS, total_svc )) )
- return WERR_NOMEM;
-
- services = tmp_services;
- i += existing_services;
- }
- else {
- if ( !(services = TALLOC_ARRAY( ctx, ENUM_SERVICES_STATUS, num_services )) )
- return WERR_NOMEM;
+ int num_services = 0;
+ int i;
+ ENUM_SERVICES_STATUS *st;
+ const char *display_name;
+
+ /* just count */
+ while ( svcctl_ops[num_services].name )
+ num_services++;
+
+ if ( !(st = TALLOC_ARRAY( ctx, ENUM_SERVICES_STATUS, num_services )) ) {
+ DEBUG(0,("enumerate_status: talloc() failed!\n"));
+ return -1;
}
-
- DEBUG(8,("enum_internal_services: Creating %d services, starting index %d\n",
- num_services, existing_services));
-
- init_unistr( &services[i].servicename, "Spooler" );
- init_unistr( &services[i].displayname, "Print Spooler" );
-
- services[i].status.type = 0x110;
- services[i].status.controls_accepted = 0x0;
- services[i].status.win32_exit_code = 0x0;
- services[i].status.service_exit_code = 0x0;
- services[i].status.check_point = 0x0;
- services[i].status.wait_hint = 0x0;
- if ( !lp_disable_spoolss() )
- services[i].status.state = SVCCTL_RUNNING;
- else
- services[i].status.state = SVCCTL_STOPPED;
-
- i++;
- init_unistr( &services[i].servicename, "NETLOGON" );
- init_unistr( &services[i].displayname, "Net Logon" );
+ for ( i=0; i<num_services; i++ ) {
+ init_unistr( &st[i].servicename, svcctl_ops[i].name );
+
+ display_name = svcctl_lookup_dispname( svcctl_ops[i].name, token );
+ init_unistr( &st[i].displayname, display_name );
+
+ svcctl_ops[i].ops->service_status( svcctl_ops[i].name, &st[i].status );
+ }
- services[i].status.type = 0x20;
- services[i].status.controls_accepted = 0x0;
- services[i].status.win32_exit_code = 0x0;
- services[i].status.service_exit_code = 0x0;
- services[i].status.check_point = 0x0;
- services[i].status.wait_hint = 0x0;
- if ( lp_servicenumber("NETLOGON") != -1 )
- services[i].status.state = SVCCTL_RUNNING;
- else
- services[i].status.state = SVCCTL_STOPPED;
-
- *added = num_services;
- *svc_ptr = services;
+ *status = st;
- return WERR_OK;
+ return num_services;
}
/********************************************************************
@@ -424,11 +389,12 @@ static WERROR enum_internal_services(TALLOC_CTX *ctx,ENUM_SERVICES_STATUS **svc_
WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, SVCCTL_R_ENUM_SERVICES_STATUS *r_u)
{
ENUM_SERVICES_STATUS *services = NULL;
- uint32 num_int_services, num_ext_services, total_services;
+ uint32 num_services;
int i = 0;
size_t buffer_size = 0;
WERROR result = WERR_OK;
SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
+ NT_USER_TOKEN *token = p->pipe_user.nt_user_token;
/* perform access checks */
@@ -438,50 +404,29 @@ WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STAT
if ( !(info->access_granted & SC_RIGHT_MGR_ENUMERATE_SERVICE) )
return WERR_ACCESS_DENIED;
- num_int_services = 0;
- num_ext_services = 0;
-
- /* num_services = str_list_count( lp_enable_svcctl() ); */
-
- /* here's where we'll read the db of external services */
- /* _svcctl_read_LSB_data(NULL,NULL); */
- /* init_svcctl_db(); */
-
- if ( !(services = TALLOC_ARRAY(p->mem_ctx, ENUM_SERVICES_STATUS, num_int_services+num_ext_services )) )
+ if ( (num_services = enumerate_status( p->mem_ctx, &services, token )) == -1 )
return WERR_NOMEM;
- if ( W_ERROR_IS_OK(enum_internal_services(p->mem_ctx, &services, 0, &num_int_services)) )
- DEBUG(8,("_svcctl_enum_services_status: Got %d internal services\n", num_int_services));
-
-#if 0
- if ( W_ERROR_IS_OK(enum_external_services(p->mem_ctx, &services, num_int_services, &num_ext_services)) )
- DEBUG(8,("_svcctl_enum_services_status: Got %d external services\n", num_ext_services));
-#endif
-
- total_services = num_int_services + num_ext_services;
-
- DEBUG(8,("_svcctl_enum_services_status: total of %d services\n", total_services ));
-
- for ( i=0; i<total_services; i++ ) {
+ for ( i=0; i<num_services; i++ ) {
buffer_size += svcctl_sizeof_enum_services_status(&services[i]);
}
buffer_size += buffer_size % 4;
if (buffer_size > q_u->buffer_size ) {
- total_services = 0;
+ num_services = 0;
result = WERR_MORE_DATA;
}
rpcbuf_init(&r_u->buffer, q_u->buffer_size, p->mem_ctx);
if ( W_ERROR_IS_OK(result) ) {
- for ( i=0; i<num_int_services+num_ext_services; i++ )
+ for ( i=0; i<num_services; i++ )
svcctl_io_enum_services_status( "", &services[i], &r_u->buffer, 0 );
}
r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
- r_u->returned = total_services;
+ r_u->returned = num_services;
if ( !(r_u->resume = TALLOC_P( p->mem_ctx, uint32 )) )
return WERR_NOMEM;
@@ -506,7 +451,7 @@ WERROR _svcctl_start_service(pipes_struct *p, SVCCTL_Q_START_SERVICE *q_u, SVCCT
if ( !(info->access_granted & SC_RIGHT_SVC_START) )
return WERR_ACCESS_DENIED;
- return info->ops->start_service();
+ return info->ops->start_service( info->name );
}
/********************************************************************
@@ -517,18 +462,27 @@ WERROR _svcctl_control_service(pipes_struct *p, SVCCTL_Q_CONTROL_SERVICE *q_u, S
SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
/* perform access checks */
- /* we only support stop so don't get complicated */
-
+
if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) )
return WERR_BADFID;
- if ( q_u->control != SVCCTL_CONTROL_STOP )
- return WERR_ACCESS_DENIED;
-
- if ( !(info->access_granted & SC_RIGHT_SVC_STOP) )
- return WERR_ACCESS_DENIED;
+ switch ( q_u->control ) {
+ case SVCCTL_CONTROL_STOP:
+ if ( !(info->access_granted & SC_RIGHT_SVC_STOP) )
+ return WERR_ACCESS_DENIED;
+
+ return info->ops->stop_service( info->name, &r_u->svc_status );
- return info->ops->stop_service( &r_u->svc_status );
+ case SVCCTL_CONTROL_INTERROGATE:
+ if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) )
+ return WERR_ACCESS_DENIED;
+
+ return info->ops->service_status( info->name, &r_u->svc_status );
+ }
+
+ /* default control action */
+
+ return WERR_ACCESS_DENIED;
}
/********************************************************************
@@ -564,11 +518,8 @@ WERROR _svcctl_enum_dependent_services( pipes_struct *p, SVCCTL_Q_ENUM_DEPENDENT
WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u )
{
- SERVICE_STATUS_PROCESS ssp;
- POLICY_HND *handle;
- SERVICE_INFO *service_info;
- pstring command;
SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
+ uint32 buffer_size;
/* perform access checks */
@@ -579,68 +530,80 @@ WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_
return WERR_ACCESS_DENIED;
/* we have to set the outgoing buffer size to the same as the
- incoming buffer size (even in the case of failure */
-
- r_u->needed = q_u->buffer_size;
-
- /* need to find the service name by the handle that is open */
- handle = &(q_u->handle);
+ incoming buffer size (even in the case of failure) */
+ rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx );
+ r_u->needed = q_u->buffer_size;
+
+ switch ( q_u->level ) {
+ case SVC_STATUS_PROCESS_INFO:
+ {
+ SERVICE_STATUS_PROCESS svc_stat_proc;
- /* get rid of the easy errors */
+ /* Get the status of the service.. */
+ info->ops->service_status( info->name, &svc_stat_proc.status );
+ svc_stat_proc.process_id = sys_getpid();
+ svc_stat_proc.service_flags = 0x0;
- if (q_u->info_level != SVC_STATUS_PROCESS_INFO) {
- DEBUG(10, ("_svcctl_query_service_status_ex : Invalid information level specified\n"));
- return WERR_UNKNOWN_LEVEL;
+ svcctl_io_service_status_process( "", &svc_stat_proc, &r_u->buffer, 0 );
+ buffer_size = sizeof(SERVICE_STATUS_PROCESS);
+ break;
+ }
+
+ default:
+ return WERR_UNKNOWN_LEVEL;
}
- service_info = find_service_info_by_hnd(p, handle);
-
- if (!service_info) {
- DEBUG(10, ("_svcctl_query_service_status_ex : Can't find the service for the handle\n"));
- return WERR_BADFID;
- }
- if (r_u->needed < (sizeof(SERVICE_STATUS_PROCESS)+sizeof(uint32)+sizeof(uint32))) {
- DEBUG(10, ("_svcctl_query_service_status_ex : buffer size of [%d] is too small.\n",r_u->needed));
- return WERR_INSUFFICIENT_BUFFER;
- }
-
- ZERO_STRUCT(ssp);
-
-#if 0
- if (!strwicmp(service_info->servicetype,"EXTERNAL"))
- ssp.type = SVCCTL_WIN32_OWN_PROC;
- else
- ssp.type = SVCCTL_WIN32_SHARED_PROC;
-#endif
+ buffer_size += buffer_size % 4;
+ r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
- /* Get the status of the service.. */
+ if (buffer_size > q_u->buffer_size )
+ return WERR_MORE_DATA;
+
+ return WERR_OK;
+}
- memset(command, 0, sizeof(command));
+/********************************************************************
+********************************************************************/
-#if 0
- slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, service_info->filename, "status");
+static WERROR fill_svc_config( TALLOC_CTX *ctx, const char *name, SERVICE_CONFIG *config, NT_USER_TOKEN *token )
+{
+ REGVAL_CTR *values;
+ REGISTRY_VALUE *val;
- DEBUG(10, ("_svcctl_query_service_status_ex: status command is [%s]\n", command));
+ /* retrieve the registry values for this service */
+
+ if ( !(values = svcctl_fetch_regvalues( name, token )) )
+ return WERR_REG_CORRUPT;
+
+ /* now fill in the individual values */
+
+ config->displayname = TALLOC_ZERO_P( ctx, UNISTR2 );
+ if ( (val = regval_ctr_getvalue( values, "DisplayName" )) != NULL )
+ init_unistr2( config->displayname, regval_sz( val ), UNI_STR_TERMINATE );
+ else
+ init_unistr2( config->displayname, name, UNI_STR_TERMINATE );
- /* TODO - wrap in privilege check */
+ if ( (val = regval_ctr_getvalue( values, "ObjectName" )) != NULL ) {
+ config->startname = TALLOC_ZERO_P( ctx, UNISTR2 );
+ init_unistr2( config->startname, regval_sz( val ), UNI_STR_TERMINATE );
+ }
+
+ if ( (val = regval_ctr_getvalue( values, "ImagePath" )) != NULL ) {
+ config->executablepath = TALLOC_ZERO_P( ctx, UNISTR2 );
+ init_unistr2( config->executablepath, regval_sz( val ), UNI_STR_TERMINATE );
+ }
- ret = smbrun(command, &fd);
- DEBUGADD(10, ("returned [%d]\n", ret));
- close(fd);
- if(ret != 0)
- DEBUG(10, ("_svcctl_query_service_status_ex: Command returned [%d]\n", ret));
+ /* a few hard coded values */
+ /* loadordergroup and dependencies are empty */
+
+ config->tag_id = 0x00000000; /* unassigned loadorder group */
+ config->service_type = SVCCTL_WIN32_OWN_PROC;
+ config->start_type = SVCCTL_DEMAND_START;
+ config->error_control = SVCCTL_SVC_ERROR_NORMAL;
- /* SET all service_stats bits here... */
- if (ret == 0) {
- ssp.state = SVCCTL_RUNNING;
- ssp.controls_accepted = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
- } else {
- ssp.state = SVCCTL_STOPPED;
- ssp.controls_accepted = 0;
- }
-#endif
+ TALLOC_FREE( values );
return WERR_OK;
}
@@ -650,10 +613,9 @@ WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_
WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u )
{
- POLICY_HND *handle;
- SERVICE_INFO *service_info;
- uint32 needed_size;
SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
+ uint32 buffer_size;
+ WERROR wresult;
/* perform access checks */
@@ -667,89 +629,19 @@ WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CON
incoming buffer size (even in the case of failure */
r_u->needed = q_u->buffer_size;
+
+ wresult = fill_svc_config( p->mem_ctx, info->name, &r_u->config, p->pipe_user.nt_user_token );
+ if ( !W_ERROR_IS_OK(wresult) )
+ return wresult;
+
+ buffer_size = svcctl_sizeof_service_config( &r_u->config );
+ r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
- /* need to find the service name by the handle that is open */
- handle = &(q_u->handle);
-
- service_info = find_service_info_by_hnd(p, handle);
-
-#if 0
- if (q_u->buffer_size < sizeof(Service_info)) {
- /* have to report need more... */
- /* TODO worst case -- should actualy calc what we need here. */
- r_u->needed = sizeof(Service_info)+sizeof(pstring)*5;
- DEBUG(10, ("_svcctl_query_service_config: NOT ENOUGH BUFFER ALLOCATED FOR RETURN DATA -- provided %d wanted %d\n",
- q_u->buffer_size,r_u->needed));
-
- return WERR_INSUFFICIENT_BUFFER;
- }
-#endif
- if (!service_info) {
- DEBUG(10, ("_svcctl_query_service_config : Can't find the service for the handle\n"));
- return WERR_BADFID;
- }
-
-#if 0
- if ( !(service_config = (SERVICE_CONFIG *)TALLOC_ZERO_P(p->mem_ctx, SERVICE_CONFIG)) )
- return WERR_NOMEM;
-#endif
-
- r_u->config.service_type = SVCCTL_WIN32_OWN_PROC;
- r_u->config.start_type = SVCCTL_DEMAND_START;
- r_u->config.error_control = SVCCTL_SVC_ERROR_IGNORE;
- r_u->config.tag_id = 0x00000000;
-
- /* Init the strings */
-
- r_u->config.executablepath = TALLOC_ZERO_P(p->mem_ctx, UNISTR2);
- r_u->config.loadordergroup = TALLOC_ZERO_P(p->mem_ctx, UNISTR2);
- r_u->config.dependencies = TALLOC_ZERO_P(p->mem_ctx, UNISTR2);
- r_u->config.startname = TALLOC_ZERO_P(p->mem_ctx, UNISTR2);
- r_u->config.displayname = TALLOC_ZERO_P(p->mem_ctx, UNISTR2);
-
-#if 0
- pstrcpy(fullpathinfo,dyn_LIBDIR);
- pstrcat(fullpathinfo,SVCCTL_SCRIPT_DIR);
- pstrcat(fullpathinfo,service_info->filename);
- /* Get and calculate the size of the fields. Note that we're still building the fields in the "too-small buffer case"
- even though we throw it away. */
-
- DEBUG(10, ("_svcctl_query_service_config: fullpath info [%s]\n",fullpathinfo));
- init_unistr2(r_u->config.executablepath,fullpathinfo,UNI_STR_TERMINATE);
- init_unistr2(r_u->config.loadordergroup,"",UNI_STR_TERMINATE);
- init_unistr2(r_u->config.dependencies,service_info->dependencies,UNI_STR_TERMINATE);
-
- /* TODO - if someone really cares, perhaps "LocalSystem" should be changed to something else here... */
-
- init_unistr2(r_u->config.startname,"LocalSystem",UNI_STR_TERMINATE);
- init_unistr2(r_u->config.displayname,service_info->servicename,UNI_STR_TERMINATE);
-#endif
-
- needed_size = 0x04 + sizeof(SERVICE_CONFIG)+ 2*(
- r_u->config.executablepath->uni_str_len +
- r_u->config.loadordergroup->uni_str_len +
- r_u->config.dependencies->uni_str_len +
- r_u->config.startname->uni_str_len +
- r_u->config.displayname->uni_str_len);
-
- DEBUG(10, ("_svcctl_query_service_config: ****** need to have a buffer of [%d], [%d] for struct \n",needed_size,
- sizeof(SERVICE_CONFIG)));
- DEBUG(10, ("\tsize of executable path : %d\n",r_u->config.executablepath->uni_str_len));
- DEBUG(10, ("\tsize of loadordergroup : %d\n", r_u->config.loadordergroup->uni_str_len));
- DEBUG(10, ("\tsize of dependencies : %d\n", r_u->config.dependencies->uni_str_len));
- DEBUG(10, ("\tsize of startname : %d\n", r_u->config.startname->uni_str_len));
- DEBUG(10, ("\tsize of displayname : %d\n", r_u->config.displayname->uni_str_len));
-
- if (q_u->buffer_size < needed_size) {
- /* have to report need more...*/
- r_u->needed = needed_size;
- DEBUG(10, ("_svcctl_query_service_config: ****** zeroing strings for return\n"));
- memset(&r_u->config,0,sizeof(SERVICE_CONFIG));
- DEBUG(10, ("_svcctl_query_service_config: Not enouh buffer provided for return -- provided %d wanted %d\n",
- q_u->buffer_size,needed_size));
- return WERR_INSUFFICIENT_BUFFER;
+ if (buffer_size > q_u->buffer_size ) {
+ ZERO_STRUCTP( &r_u->config );
+ return WERR_INSUFFICIENT_BUFFER;
}
-
+
return WERR_OK;
}
@@ -758,9 +650,8 @@ WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CON
WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u )
{
- POLICY_HND *handle;
- SERVICE_INFO *service_info;
SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
+ uint32 buffer_size;
/* perform access checks */
@@ -773,55 +664,84 @@ WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CO
/* we have to set the outgoing buffer size to the same as the
incoming buffer size (even in the case of failure */
- r_u->needed = q_u->buffer_size;
- r_u->description = NULL;
- r_u->returned = q_u->buffer_size;
- r_u->offset = 4;
+ rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx );
+ r_u->needed = q_u->buffer_size;
- handle = &(q_u->handle);
+ switch ( q_u->level ) {
+ case SERVICE_CONFIG_DESCRIPTION:
+ {
+ SERVICE_DESCRIPTION desc_buf;
+ const char *description;
+
+ description = svcctl_lookup_description( info->name, p->pipe_user.nt_user_token );
+
+ ZERO_STRUCTP( &desc_buf );
- service_info = find_service_info_by_hnd(p, handle);
+ init_service_description_buffer( &desc_buf, description );
+ svcctl_io_service_description( "", &desc_buf, &r_u->buffer, 0 );
+ buffer_size = svcctl_sizeof_service_description( &desc_buf );
- if (!service_info) {
- DEBUG(10, ("_svcctl_query_service_config2 : Can't find the service for the handle\n"));
- return WERR_BADFID;
- }
-
- /*
- TODO - perhaps move the RPC_DATA_BLOB into the R_QUERY_SERVICE_CONFIG structure, and to the processing in here, vs
- in the *r_query_config2 marshalling routine...
- */
-
-#if 0
- if (SERVICE_CONFIG_DESCRIPTION == q_u->info_level) {
- if (service_info && service_info->shortdescription) {
- /* length of the string, plus the terminator... */
- string_buffer_size = strlen(service_info->shortdescription)+1;
- DEBUG(10, ("_svcctl_query_service_config: copying the description [%s] length [%d]\n",
- service_info->shortdescription,string_buffer_size));
-
- if (q_u->buffer_size >= ((string_buffer_size)*2+4)) {
- r_u->description = TALLOC_ZERO_P(p->mem_ctx, UNISTR2);
- if (!r_u->description) return WERR_NOMEM;
- init_unistr2(r_u->description,service_info->shortdescription,UNI_STR_TERMINATE);
- }
+ break;
}
- else {
- string_buffer_size = 0;
- }
- DEBUG(10, ("_svcctl_query_service_config2: buffer needed is [%x], return buffer size is [%x]\n",
- string_buffer_size,q_u->buffer_size));
- if (((string_buffer_size)*2+4) > q_u->buffer_size) {
- r_u->needed = (string_buffer_size+1)*2+4;
- DEBUG(10, ("_svcctl_query_service_config2: INSUFFICIENT BUFFER\n"));
- return WERR_INSUFFICIENT_BUFFER;
+ break;
+ case SERVICE_CONFIG_FAILURE_ACTIONS:
+ {
+ SERVICE_FAILURE_ACTIONS actions;
+
+ /* nothing to say...just service the request */
+
+ ZERO_STRUCTP( &actions );
+ svcctl_io_service_fa( "", &actions, &r_u->buffer, 0 );
+ buffer_size = svcctl_sizeof_service_fa( &actions );
+
+ break;
}
- DEBUG(10, ("_svcctl_query_service_config2: returning ok, needed is [%x], buffer size is [%x]\n",
- r_u->needed,q_u->buffer_size));
+ break;
+
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ buffer_size += buffer_size % 4;
+ r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
- return WERR_OK;
- }
-#endif
+ if (buffer_size > q_u->buffer_size )
+ return WERR_INSUFFICIENT_BUFFER;
- return WERR_ACCESS_DENIED;
+ return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _svcctl_lock_service_db( pipes_struct *p, SVCCTL_Q_LOCK_SERVICE_DB *q_u, SVCCTL_R_LOCK_SERVICE_DB *r_u )
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle );
+
+ /* perform access checks */
+
+ if ( !info || (info->type != SVC_HANDLE_IS_SCM) )
+ return WERR_BADFID;
+
+ if ( !(info->access_granted & SC_RIGHT_MGR_LOCK) )
+ return WERR_ACCESS_DENIED;
+
+ /* Just open a handle. Doesn't actually lock anything */
+
+ return create_open_service_handle( p, &r_u->h_lock, SVC_HANDLE_IS_DBLOCK, NULL, 0 );
+;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _svcctl_unlock_service_db( pipes_struct *p, SVCCTL_Q_UNLOCK_SERVICE_DB *q_u, SVCCTL_R_UNLOCK_SERVICE_DB *r_u )
+{
+ SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->h_lock );
+
+
+ if ( !info || (info->type != SVC_HANDLE_IS_DBLOCK) )
+ return WERR_BADFID;
+
+ return close_policy_hnd( p, &q_u->h_lock) ? WERR_OK : WERR_BADFID;
}