diff options
author | Gerald Carter <jerry@samba.org> | 2005-09-30 17:13:37 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:04:48 -0500 |
commit | 54abd2aa66069e6baf7769c496f46d9dba18db39 (patch) | |
tree | 9cf8e88168011797319ba9e9866749201b1eac1e /source3/rpc_server | |
parent | 4a2cc231d22a82ed21771a72508f15d21ed63227 (diff) | |
download | samba-54abd2aa66069e6baf7769c496f46d9dba18db39.tar.gz samba-54abd2aa66069e6baf7769c496f46d9dba18db39.tar.xz samba-54abd2aa66069e6baf7769c496f46d9dba18db39.zip |
r10656: BIG merge from trunk. Features not copied over
* \PIPE\unixinfo
* winbindd's {group,alias}membership new functions
* winbindd's lookupsids() functionality
* swat (trunk changes to be reverted as per discussion with Deryck)
(This used to be commit 939c3cb5d78e3a2236209b296aa8aba8bdce32d3)
Diffstat (limited to 'source3/rpc_server')
-rw-r--r-- | source3/rpc_server/srv_eventlog.c | 6 | ||||
-rw-r--r-- | source3/rpc_server/srv_eventlog_nt.c | 1585 | ||||
-rw-r--r-- | source3/rpc_server/srv_lsa_hnd.c | 6 | ||||
-rw-r--r-- | source3/rpc_server/srv_lsa_nt.c | 7 | ||||
-rw-r--r-- | source3/rpc_server/srv_netlog_nt.c | 269 | ||||
-rw-r--r-- | source3/rpc_server/srv_ntsvcs.c | 220 | ||||
-rw-r--r-- | source3/rpc_server/srv_ntsvcs_nt.c | 174 | ||||
-rw-r--r-- | source3/rpc_server/srv_pipe.c | 1863 | ||||
-rw-r--r-- | source3/rpc_server/srv_pipe_hnd.c | 217 | ||||
-rw-r--r-- | source3/rpc_server/srv_reg.c | 57 | ||||
-rw-r--r-- | source3/rpc_server/srv_reg_nt.c | 436 | ||||
-rw-r--r-- | source3/rpc_server/srv_samr_nt.c | 153 | ||||
-rw-r--r-- | source3/rpc_server/srv_samr_util.c | 4 | ||||
-rw-r--r-- | source3/rpc_server/srv_spoolss_nt.c | 55 | ||||
-rw-r--r-- | source3/rpc_server/srv_srvsvc_nt.c | 5 | ||||
-rw-r--r-- | source3/rpc_server/srv_svcctl.c | 76 | ||||
-rw-r--r-- | source3/rpc_server/srv_svcctl_nt.c | 694 |
17 files changed, 3403 insertions, 2424 deletions
diff --git a/source3/rpc_server/srv_eventlog.c b/source3/rpc_server/srv_eventlog.c index 65b10e8fe4..ae15d43f4b 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 a9b0c9bed8..414c99d28e 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 68072b528a..7da87d5b93 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 021f1dc8e0..15d420538e 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 15827a8b55..5aefe3ca3c 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 0000000000..48910dbee2 --- /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 0000000000..0bb9154aaf --- /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 63e8d2f5cd..ba6d9704e8 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, ¤t_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 83b78f8d2f..205223190b 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 871b1a9f12..1772524038 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 a405948864..4db5ed0ed6 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, ®_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 656241a73f..b69f03a3a2 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 24869d5d2b..1d9a8ecd1d 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 cda3f26137..5233d6c252 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(¬ify_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(¬ify_cli); - cli_ulogoff(¬ify_cli); - cli_shutdown(¬ify_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( ¬ify_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(¬ify_cli, client_ip, unix_printer)) + if(!spoolss_connect_to_client(¬ify_cli, ¬ify_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(¬ify_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 e9dd015421..9643b2a724 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 6ba26414d3..31d8bbe9b3 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 538b97a2b1..e8df2acb22 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; } |