From 5d1cb8e79edea9e8581d3c2c9dd297310cd9a98c Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Wed, 23 Mar 2005 23:26:33 +0000 Subject: r6014: rather large change set.... pulling back all recent rpc changes from trunk into 3.0. I've tested a compile and so don't think I've missed any files. But if so, just mail me and I'll clean backup in a couple of hours. Changes include \winreg, \eventlog, \svcctl, and general parse_misc.c updates. I am planning on bracketing the event code with an #ifdef ENABLE_EVENTLOG until I finish merging Marcin's changes (very soon). (This used to be commit 4e0ac63c36527cd8c52ef720cae17e84f67e7221) --- source3/rpc_server/srv_eventlog.c | 206 ++++++++ source3/rpc_server/srv_eventlog_nt.c | 923 +++++++++++++++++++++++++++++++++++ source3/rpc_server/srv_lsa_ds_nt.c | 7 +- source3/rpc_server/srv_netlog.c | 2 +- source3/rpc_server/srv_pipe.c | 7 + source3/rpc_server/srv_reg.c | 67 ++- source3/rpc_server/srv_reg_nt.c | 141 ++++-- source3/rpc_server/srv_spoolss_nt.c | 19 +- source3/rpc_server/srv_svcctl.c | 294 +++++++++++ source3/rpc_server/srv_svcctl_nt.c | 291 +++++++++++ 10 files changed, 1875 insertions(+), 82 deletions(-) create mode 100644 source3/rpc_server/srv_eventlog.c create mode 100644 source3/rpc_server/srv_eventlog_nt.c create mode 100644 source3/rpc_server/srv_svcctl.c create mode 100644 source3/rpc_server/srv_svcctl_nt.c (limited to 'source3/rpc_server') diff --git a/source3/rpc_server/srv_eventlog.c b/source3/rpc_server/srv_eventlog.c new file mode 100644 index 0000000000..07aebcd2fa --- /dev/null +++ b/source3/rpc_server/srv_eventlog.c @@ -0,0 +1,206 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * Copyright (C) Marcin Krzysztof Porwit 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_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; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!(eventlog_io_q_open_eventlog("", &q_u, data, 0))) { + DEBUG(0, ("eventlog_io_q_open_eventlog: unable to unmarshall EVENTLOG_Q_OPEN_EVENTLOG.\n")); + return False; + } + + r_u.status = _eventlog_open_eventlog(p, &q_u, &r_u); + + if (!(eventlog_io_r_open_eventlog("", &r_u, rdata, 0))) { + DEBUG(0, ("eventlog_io_r_open_eventlog: unable to marshall EVENTLOG_R_OPEN_EVENTLOG.\n")); + return False; + } + + return True; +} + +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; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!(eventlog_io_q_close_eventlog("", &q_u, data, 0))) { + DEBUG(0, ("eventlog_io_q_close_eventlog: unable to unmarshall EVENTLOG_Q_CLOSE_EVENTLOG.\n")); + return False; + } + + r_u.status = _eventlog_close_eventlog(p, &q_u, &r_u); + + if (!(eventlog_io_r_close_eventlog("", &r_u, rdata, 0))) { + DEBUG(0, ("eventlog_io_r_close_eventlog: unable to marshall EVENTLOG_R_CLOSE_EVENTLOG.\n")); + return False; + } + + return True; +} + +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; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!(eventlog_io_q_get_num_records("", &q_u, data, 0))) { + DEBUG(0, ("eventlog_io_q_get_num_records: unable to unmarshall EVENTLOG_Q_GET_NUM_RECORDS.\n")); + return False; + } + + r_u.status = _eventlog_get_num_records(p, &q_u, &r_u); + + if (!(eventlog_io_r_get_num_records("", &r_u, rdata, 0))) { + DEBUG(0, ("eventlog_io_r_get_num_records: unable to marshall EVENTLOG_R_GET_NUM_RECORDS.\n")); + return False; + } + + return True; +} + +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; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!(eventlog_io_q_get_oldest_entry("", &q_u, data, 0))) { + DEBUG(0, ("eventlog_io_q_get_oldest_entry: unable to unmarshall EVENTLOG_Q_GET_OLDEST_ENTRY.\n")); + return False; + } + + r_u.status = _eventlog_get_oldest_entry(p, &q_u, &r_u); + + if (!(eventlog_io_r_get_oldest_entry("", &r_u, rdata, 0))) { + DEBUG(0, ("eventlog_io_r_get_oldest_entry: unable to marshall EVENTLOG_R_GET_OLDEST_ENTRY.\n")); + return False; + } + + return True; +} + +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; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!(eventlog_io_q_read_eventlog("", &q_u, data, 0))) { + DEBUG(0, ("eventlog_io_q_read_eventlog: unable to unmarshall EVENTLOG_Q_READ_EVENTLOG.\n")); + return False; + } + + r_u.status = _eventlog_read_eventlog(p, &q_u, &r_u); + + if (!(eventlog_io_r_read_eventlog("", &q_u, &r_u, rdata, 0))) { + DEBUG(0, ("eventlog_io_r_read_eventlog: unable to marshall EVENTLOG_R_READ_EVENTLOG.\n")); + return False; + } + + return True; +} + +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; + + ZERO_STRUCT(q_u); + ZERO_STRUCT(r_u); + + if (!(eventlog_io_q_clear_eventlog("", &q_u, data, 0))) { + DEBUG(0, ("eventlog_io_q_clear_eventlog: unable to unmarshall EVENTLOG_Q_CLEAR_EVENTLOG.\n")); + return False; + } + + r_u.status = _eventlog_clear_eventlog(p, &q_u, &r_u); + + if (!(eventlog_io_r_clear_eventlog("", &r_u, rdata, 0))) { + DEBUG(0, ("eventlog_io_q_clear_eventlog: unable to marshall EVENTLOG_Q_CLEAR_EVENTLOG.\n")); + return False; + } + + return True; +} + +/* + \pipe\eventlog commands +*/ +struct api_struct api_eventlog_cmds[] = +{ + {"EVENTLOG_OPENEVENTLOG", EVENTLOG_OPENEVENTLOG, api_eventlog_open_eventlog }, + {"EVENTLOG_CLOSEVENTLOG", EVENTLOG_CLOSEEVENTLOG, api_eventlog_close_eventlog }, + {"EVENTLOG_GETNUMRECORDS", EVENTLOG_GETNUMRECORDS, api_eventlog_get_num_records }, + {"EVENTLOG_GETOLDESTENTRY", EVENTLOG_GETOLDESTENTRY, api_eventlog_get_oldest_entry }, + {"EVENTLOG_READEVENTLOG", EVENTLOG_READEVENTLOG, api_eventlog_read_eventlog }, + {"EVENTLOG_CLEAREVENTLOG", EVENTLOG_CLEAREVENTLOG, api_eventlog_clear_eventlog } +}; + +NTSTATUS rpc_eventlog_init(void) +{ + return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, + "eventlog", "eventlog", api_eventlog_cmds, + sizeof(api_eventlog_cmds)/sizeof(struct api_struct)); +} + +void eventlog_get_pipe_fns(struct api_struct **fns, int *n_fns) +{ + *fns = api_eventlog_cmds; + *n_fns = sizeof(api_eventlog_cmds) / sizeof(struct api_struct); +} diff --git a/source3/rpc_server/srv_eventlog_nt.c b/source3/rpc_server/srv_eventlog_nt.c new file mode 100644 index 0000000000..7501434a13 --- /dev/null +++ b/source3/rpc_server/srv_eventlog_nt.c @@ -0,0 +1,923 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * Copyright (C) Marcin Krzysztof Porwit 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 + +typedef struct eventlog_info +{ + /* 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; +} Eventlog_info; + +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); +} + +static Eventlog_info *find_eventlog_info_by_hnd(pipes_struct *p, + POLICY_HND *handle) +{ + Eventlog_info *info = NULL; + + if(!(find_policy_by_hnd(p,handle,(void **)&info))) + { + DEBUG(2,("find_eventlog_info_by_hnd: eventlog not found.\n")); + } + + return info; +} + +void policy_handle_to_string(POLICY_HND *handle, fstring *dest) +{ + 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]); +} + +/** + * Callout to open the specified event log + * + * smbrun calling convention -- + * INPUT: + * 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) +{ + 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; + } + + 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 open [%s].\n", info->source_log_file_name)); + file_lines_free(qlines); + return True; + } + } + + 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) +{ + 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)) + return WERR_NOMEM; + + policy_handle_to_string(&r_u->handle, &info->handle_string); + + if(!(_eventlog_open_eventlog_hook(info))) + return WERR_BADFILE; + + return WERR_OK; +} +/** + * Callout to get the number of records in the specified event log + * + * smbrun calling convention -- + * INPUT: + * 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); + + if(numlines) + { + DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0])); + sscanf(qlines[0], "%d", &(info->num_records)); + file_lines_free(qlines); + return True; + } + + file_lines_free(qlines); + return False; +} + +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(!q_u || !r_u) + return WERR_NOMEM; + + handle = &(q_u->handle); + info = find_eventlog_info_by_hnd(p, handle); + + if(!(_eventlog_get_num_records_hook(info))) + return WERR_BADFILE; + + r_u->num_records = info->num_records; + + return WERR_OK; +} +/** + * Callout to find the oldest record in the log + * + * smbrun calling convention -- + * INPUT: + * OUTPUT: If there are entries in the event log, the index of the + * 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) +{ + Eventlog_info *info = NULL; + POLICY_HND *handle = NULL; + + if(!q_u || !r_u) + return WERR_NOMEM; + + handle = &(q_u->handle); + info = find_eventlog_info_by_hnd(p, handle); + + if(!(_eventlog_get_oldest_entry_hook(info))) + return WERR_BADFILE; + + r_u->oldest_entry = info->oldest_entry; + + return WERR_OK; +} + +/** + * Callout to close the specified event log + * + * smbrun calling convention -- + * INPUT: + * 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) +{ + 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; + } + + 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 close [%s].\n", info->source_log_file_name)); + file_lines_free(qlines); + return True; + } + } + + file_lines_free(qlines); + 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; + + if(!q_u || !r_u) + return WERR_NOMEM; + + 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; +} + +static BOOL _eventlog_read_parse_line(char *line, Eventlog_entry *entry) +{ + char *start = NULL, *stop = NULL; + pstring temp; + int temp_len = 0, i; + + start = line; + + if(start == NULL || strlen(start) == 0) + return False; + 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; + } + } +/* + 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)); + sscanf(stop+1, "%s", temp); + temp_len = strlen(temp); + 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)); + sscanf(stop+1, "%s", temp); + temp_len = strlen(temp); + 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)); + sscanf(stop+1, "%s", temp); + temp_len = strlen(temp); + 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. */ + return True; + } + return True; +} +/** + * Callout to read entries from the specified event log + * + * smbrun calling convention -- + * INPUT: + * where direction is either "forward" or "backward", the starting record is somewhere + * between the oldest_record and oldest_record+num_records, and the buffer size is the + * maximum size of the buffer that the client can accomodate. + * OUTPUT: A buffer containing a set of entries, one to a line, of the format: + * line type:line data + * These are the allowed line types: + * RS1:(uint32) - reserved. All M$ entries seem to have int(1699505740) for now + * RCN:(uint32) - record number of the record, however it may be calculated by the script + * TMG:(uint32) - time generated, seconds since January 1, 1970, 0000 UTC + * TMW:(uint32) - time written, seconds since January 1, 1970, 0000 UTC + * EID:(uint32) - eventlog source defined event identifier. If there's a stringfile for the event, it is an index into that + * ETP:(uint16) - eventlog type - one of ERROR, WARNING, INFO, AUDIT_SUCCESS, AUDIT_FAILURE + * ECT:(uint16) - event category - depends on the eventlog generator... + * RS2:(uint16) - reserved, make it 0000 + * CRN:(uint32) - reserved, make it 00000000 for now + * USL:(uint32) - user SID length. No sid? Make this 0. Must match SID below + * SRC:[(uint8)] - Name of the source, for example ccPwdSvc, in hex bytes. Can not be multiline. + * SRN:[(uint8)] - Name of the computer on which this is generated, the short hostname usually. + * SID:[(uint8)] - User sid if one exists. Must be present even if there is no SID. + * STR:[(uint8)] - String data. One string per line. Multiple strings can be specified using consecutive "STR" lines, + * up to a total aggregate string length of 1024 characters. + * DAT:[(uint8)] - The user-defined data portion of the event log. Can not be multiple lines. + */ +static BOOL _eventlog_read_eventlog_hook(Eventlog_info *info, Eventlog_entry *entry, const char *direction, int starting_record, int buffer_size, BOOL *eof) +{ + char *cmd = lp_eventlog_read_cmd(); + char **qlines; + pstring command; + int numlines = 0; + int ret; + int fd = -1; + int i; + + if(info == NULL) + 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); + + 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) + { + for(i = 0; i < numlines; i++) + { + DEBUGADD(10, ("Line[%d] = %s\n", i, qlines[i])); + _eventlog_read_parse_line(qlines[i], entry); + } + file_lines_free(qlines); + return True; + } + else + *eof = True; + + file_lines_free(qlines); + return False; +} + +static BOOL _eventlog_read_prepare_data_buffer(prs_struct *ps, + EVENTLOG_Q_READ_EVENTLOG *q_u, + EVENTLOG_R_READ_EVENTLOG *r_u, + Eventlog_entry *entry) +{ + uint8 *offset; + Eventlog_entry *new = NULL, *insert_point = NULL; + + new = PRS_ALLOC_MEM(ps, Eventlog_entry, 1); + if(new == NULL) + return False; + + 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 False; + 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; + /* Now that we've massaged the current entry, copy it into the new entry and add it + to end of the list */ + insert_point=r_u->entry; + + if (NULL == insert_point) + { + r_u->entry = new; + new->next = NULL; + } + else + { + while ((NULL != insert_point->next)) + { + insert_point=insert_point->next; + } + new->next = NULL; + insert_point->next = new; + } + + memcpy(&(new->record), &entry->record, sizeof(Eventlog_record)); + memcpy(&(new->data_record), &entry->data_record, sizeof(Eventlog_data_record)); + new->data = entry->data; + + r_u->num_records++; + r_u->num_bytes_in_resp += entry->record.length; + + return True; +} + +WERROR _eventlog_read_eventlog(pipes_struct *p, + EVENTLOG_Q_READ_EVENTLOG *q_u, + EVENTLOG_R_READ_EVENTLOG *r_u) +{ + Eventlog_info *info = NULL; + POLICY_HND *handle; + Eventlog_entry entry; + BOOL eof = False; + const char *direction = ""; + int starting_record; + prs_struct *ps; + + if(!q_u || !r_u) + return WERR_NOMEM; + + handle = &(q_u->handle); + info = find_eventlog_info_by_hnd(p, handle); + ps = &p->out_data.rdata; + /* 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) + starting_record = q_u->offset; + else + starting_record = info->oldest_entry; + if(q_u->flags & EVENTLOG_FORWARDS_READ) + direction = "forward"; + else if(q_u->flags & EVENTLOG_BACKWARDS_READ) + direction = "backward"; + + do + { + ZERO_STRUCT(entry); + if(!(_eventlog_read_eventlog_hook(info, &entry, direction, starting_record, q_u->max_read_size, &eof))) + { + if(eof == False) + return WERR_NOMEM; + } + if(eof == False) + { + /* only if the read hook returned data */ + if(!(_eventlog_read_prepare_data_buffer(ps, q_u, r_u, &entry))) + return WERR_NOMEM; + DEBUG(10, ("_eventlog_read_eventlog: read [%d] bytes out of a max of [%d].\n", + r_u->num_bytes_in_resp, + q_u->max_read_size)); + } + } while((r_u->num_bytes_in_resp <= q_u->max_read_size) && (eof != True)); + + return WERR_OK; +} +/** + * Callout to clear (and optionally backup) a specified event log + * + * smbrun calling convention -- + * INPUT: + * OUTPUT: A single line with the string "SUCCESS" if the command succeeded. + * Otherwise it is assumed to have failed + * + * INPUT: + * OUTPUT: A single line with the string "SUCCESS" if the command succeeded. + * Otherwise it is assumed to have failed + * 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) +{ + 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; + } + + 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->source_log_file_name)); + file_lines_free(qlines); + return True; + } + } + + file_lines_free(qlines); + return False; +} + +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; + + if(!q_u || !r_u) + return WERR_NOMEM; + + handle = &(q_u->handle); + info = find_eventlog_info_by_hnd(p, handle); + memset(backup_file_name, 0, 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; +} diff --git a/source3/rpc_server/srv_lsa_ds_nt.c b/source3/rpc_server/srv_lsa_ds_nt.c index d0b7a299be..b410af8ded 100644 --- a/source3/rpc_server/srv_lsa_ds_nt.c +++ b/source3/rpc_server/srv_lsa_ds_nt.c @@ -46,6 +46,9 @@ static NTSTATUS fill_dsrole_dominfo_basic(TALLOC_CTX *ctx, DSROLE_PRIMARY_DOMAIN return NT_STATUS_NO_MEMORY; } + get_mydnsdomname(dnsdomain); + strlower_m(dnsdomain); + switch ( lp_server_role() ) { case ROLE_STANDALONE: basic->machine_role = DSROLE_STANDALONE_SRV; @@ -58,16 +61,12 @@ static NTSTATUS fill_dsrole_dominfo_basic(TALLOC_CTX *ctx, DSROLE_PRIMARY_DOMAIN basic->flags = DSROLE_PRIMARY_DS_RUNNING|DSROLE_PRIMARY_DS_MIXED_MODE; if ( secrets_fetch_domain_guid( lp_workgroup(), &basic->domain_guid ) ) basic->flags |= DSROLE_PRIMARY_DOMAIN_GUID_PRESENT; - get_mydnsdomname(dnsdomain); - strlower_m(dnsdomain); break; case ROLE_DOMAIN_PDC: basic->machine_role = DSROLE_PDC; basic->flags = DSROLE_PRIMARY_DS_RUNNING|DSROLE_PRIMARY_DS_MIXED_MODE; if ( secrets_fetch_domain_guid( lp_workgroup(), &basic->domain_guid ) ) basic->flags |= DSROLE_PRIMARY_DOMAIN_GUID_PRESENT; - get_mydnsdomname(dnsdomain); - strlower_m(dnsdomain); break; } diff --git a/source3/rpc_server/srv_netlog.c b/source3/rpc_server/srv_netlog.c index 705b629732..a45a7eebf6 100644 --- a/source3/rpc_server/srv_netlog.c +++ b/source3/rpc_server/srv_netlog.c @@ -299,7 +299,7 @@ static BOOL api_net_logon_ctrl(pipes_struct *p) r_u.status = _net_logon_ctrl(p, &q_u, &r_u); if(!net_io_r_logon_ctrl("", &r_u, rdata, 0)) { - DEBUG(0,("net_reply_logon_ctrl2: Failed to marshall NET_R_LOGON_CTRL2.\n")); + DEBUG(0,("net_reply_logon_ctrl2: Failed to marshall NET_R_LOGON_CTRL.\n")); return False; } diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index 01e91ce6c5..ab21f60902 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -765,6 +765,7 @@ BOOL check_bind_req(struct pipes_struct *p, RPC_IFACE* abstract, 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) @@ -1631,6 +1632,12 @@ void get_pipe_fns( int idx, struct api_struct **fns, int *n_fns ) case PI_NETDFS: netdfs_get_pipe_fns( &cmds, &n_cmds ); break; + case PI_SVCCTL: + svcctl_get_pipe_fns( &cmds, &n_cmds ); + break; + case PI_EVENTLOG: + eventlog_get_pipe_fns( &cmds, &n_cmds ); + break; #ifdef DEVELOPER case PI_ECHO: echo_get_pipe_fns( &cmds, &n_cmds ); diff --git a/source3/rpc_server/srv_reg.c b/source3/rpc_server/srv_reg.c index b780be0aff..b2b3920e9e 100644 --- a/source3/rpc_server/srv_reg.c +++ b/source3/rpc_server/srv_reg.c @@ -63,8 +63,8 @@ static BOOL api_reg_close(pipes_struct *p) static BOOL api_reg_open_hklm(pipes_struct *p) { - REG_Q_OPEN_HKLM q_u; - REG_R_OPEN_HKLM r_u; + 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; @@ -72,12 +72,12 @@ static BOOL api_reg_open_hklm(pipes_struct *p) ZERO_STRUCT(r_u); /* grab the reg open */ - if(!reg_io_q_open_hklm("", &q_u, data, 0)) + if(!reg_io_q_open_hive("", &q_u, data, 0)) return False; r_u.status = _reg_open_hklm(p, &q_u, &r_u); - if(!reg_io_r_open_hklm("", &r_u, rdata, 0)) + if(!reg_io_r_open_hive("", &r_u, rdata, 0)) return False; return True; @@ -89,8 +89,8 @@ static BOOL api_reg_open_hklm(pipes_struct *p) static BOOL api_reg_open_hku(pipes_struct *p) { - REG_Q_OPEN_HKU q_u; - REG_R_OPEN_HKU r_u; + 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; @@ -98,12 +98,12 @@ static BOOL api_reg_open_hku(pipes_struct *p) ZERO_STRUCT(r_u); /* grab the reg open */ - if(!reg_io_q_open_hku("", &q_u, data, 0)) + if(!reg_io_q_open_hive("", &q_u, data, 0)) return False; r_u.status = _reg_open_hku(p, &q_u, &r_u); - if(!reg_io_r_open_hku("", &r_u, rdata, 0)) + if(!reg_io_r_open_hive("", &r_u, rdata, 0)) return False; return True; @@ -115,8 +115,8 @@ static BOOL api_reg_open_hku(pipes_struct *p) static BOOL api_reg_open_hkcr(pipes_struct *p) { - REG_Q_OPEN_HKCR q_u; - REG_R_OPEN_HKCR r_u; + 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; @@ -124,12 +124,12 @@ static BOOL api_reg_open_hkcr(pipes_struct *p) ZERO_STRUCT(r_u); /* grab the reg open */ - if(!reg_io_q_open_hkcr("", &q_u, data, 0)) + if(!reg_io_q_open_hive("", &q_u, data, 0)) return False; r_u.status = _reg_open_hkcr(p, &q_u, &r_u); - if(!reg_io_r_open_hkcr("", &r_u, rdata, 0)) + if(!reg_io_r_open_hive("", &r_u, rdata, 0)) return False; return True; @@ -215,6 +215,32 @@ static BOOL api_reg_shutdown(pipes_struct *p) return True; } +/******************************************************************* + api_reg_shutdown_ex + ********************************************************************/ + +static BOOL api_reg_shutdown_ex(pipes_struct *p) +{ + REG_Q_SHUTDOWN_EX q_u; + REG_R_SHUTDOWN_EX 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 shutdown ex */ + if(!reg_io_q_shutdown_ex("", &q_u, data, 0)) + return False; + + r_u.status = _reg_shutdown_ex(p, &q_u, &r_u); + + if(!reg_io_r_shutdown_ex("", &r_u, rdata, 0)) + return False; + + return True; +} + /******************************************************************* api_reg_abort_shutdown ********************************************************************/ @@ -268,25 +294,25 @@ static BOOL api_reg_query_key(pipes_struct *p) } /******************************************************************* - api_reg_unknown_1a + api_reg_getversion ********************************************************************/ -static BOOL api_reg_unknown_1a(pipes_struct *p) +static BOOL api_reg_getversion(pipes_struct *p) { - REG_Q_UNKNOWN_1A q_u; - REG_R_UNKNOWN_1A r_u; + REG_Q_GETVERSION q_u; + REG_R_GETVERSION 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(!reg_io_q_unknown_1a("", &q_u, data, 0)) + if(!reg_io_q_getversion("", &q_u, data, 0)) return False; - r_u.status = _reg_unknown_1a(p, &q_u, &r_u); + r_u.status = _reg_getversion(p, &q_u, &r_u); - if(!reg_io_r_unknown_1a("", &r_u, rdata, 0)) + if(!reg_io_r_getversion("", &r_u, rdata, 0)) return False; return True; @@ -383,8 +409,9 @@ static struct api_struct api_reg_cmds[] = { "REG_QUERY_KEY" , REG_QUERY_KEY , api_reg_query_key }, { "REG_INFO" , REG_INFO , api_reg_info }, { "REG_SHUTDOWN" , REG_SHUTDOWN , api_reg_shutdown }, + { "REG_SHUTDOWN_EX" , REG_SHUTDOWN_EX , api_reg_shutdown_ex }, { "REG_ABORT_SHUTDOWN" , REG_ABORT_SHUTDOWN , api_reg_abort_shutdown }, - { "REG_UNKNOWN_1A" , REG_UNKNOWN_1A , api_reg_unknown_1a }, + { "REG_GETVERSION" , REG_GETVERSION , api_reg_getversion }, { "REG_SAVE_KEY" , REG_SAVE_KEY , api_reg_save_key } }; diff --git a/source3/rpc_server/srv_reg_nt.c b/source3/rpc_server/srv_reg_nt.c index c11e0d59a0..f0d831cc6a 100644 --- a/source3/rpc_server/srv_reg_nt.c +++ b/source3/rpc_server/srv_reg_nt.c @@ -5,7 +5,7 @@ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997. * Copyright (C) Paul Ashton 1997. * Copyright (C) Jeremy Allison 2001. - * Copyright (C) Gerald Carter 2002. + * Copyright (C) Gerald Carter 2002-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 @@ -291,7 +291,7 @@ 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_HKLM *q_u, REG_R_OPEN_HKLM *r_u) +WERROR _reg_open_hklm(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u) { return open_registry_key( p, &r_u->pol, NULL, KEY_HKLM, 0x0 ); } @@ -299,7 +299,7 @@ WERROR _reg_open_hklm(pipes_struct *p, REG_Q_OPEN_HKLM *q_u, REG_R_OPEN_HKLM *r_ /******************************************************************* ********************************************************************/ -WERROR _reg_open_hkcr(pipes_struct *p, REG_Q_OPEN_HKCR *q_u, REG_R_OPEN_HKCR *r_u) +WERROR _reg_open_hkcr(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u) { return open_registry_key( p, &r_u->pol, NULL, KEY_HKCR, 0x0 ); } @@ -307,7 +307,7 @@ WERROR _reg_open_hkcr(pipes_struct *p, REG_Q_OPEN_HKCR *q_u, REG_R_OPEN_HKCR *r_ /******************************************************************* ********************************************************************/ -WERROR _reg_open_hku(pipes_struct *p, REG_Q_OPEN_HKU *q_u, REG_R_OPEN_HKU *r_u) +WERROR _reg_open_hku(pipes_struct *p, REG_Q_OPEN_HIVE *q_u, REG_R_OPEN_HIVE *r_u) { return open_registry_key( p, &r_u->pol, NULL, KEY_HKU, 0x0 ); } @@ -328,7 +328,7 @@ WERROR _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY if ( !key ) return WERR_BADFID; /* This will be reported as an RPC fault anyway. */ - rpcstr_pull(name,q_u->uni_name.buffer,sizeof(name),q_u->uni_name.uni_str_len*2,0); + rpcstr_pull( name, q_u->name.string->buffer, sizeof(name), q_u->name.string->uni_str_len*2, 0 ); result = open_registry_key( p, &pol, key, name, 0x0 ); @@ -362,7 +362,7 @@ WERROR _reg_info(pipes_struct *p, REG_Q_INFO *q_u, REG_R_INFO *r_u) DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->name)); - rpcstr_pull(name, q_u->uni_type.buffer, sizeof(name), q_u->uni_type.uni_str_len*2, 0); + 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)); @@ -439,7 +439,7 @@ WERROR _reg_info(pipes_struct *p, REG_Q_INFO *q_u, REG_R_INFO *r_u) out: - new_init_reg_r_info(q_u->ptr_buf, r_u, val, status); + init_reg_r_info(q_u->ptr_buf, r_u, val, status); regval_ctr_destroy( ®vals ); free_registry_value( val ); @@ -485,22 +485,22 @@ WERROR _reg_query_key(pipes_struct *p, REG_Q_QUERY_KEY *q_u, REG_R_QUERY_KEY *r_ /***************************************************************************** - Implementation of REG_UNKNOWN_1A + Implementation of REG_GETVERSION ****************************************************************************/ -WERROR _reg_unknown_1a(pipes_struct *p, REG_Q_UNKNOWN_1A *q_u, REG_R_UNKNOWN_1A *r_u) +WERROR _reg_getversion(pipes_struct *p, REG_Q_GETVERSION *q_u, REG_R_GETVERSION *r_u) { WERROR status = WERR_OK; REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol ); - DEBUG(5,("_reg_unknown_1a: Enter\n")); + DEBUG(5,("_reg_getversion: Enter\n")); if ( !regkey ) return WERR_BADFID; /* This will be reported as an RPC fault anyway. */ r_u->unknown = 0x00000005; /* seems to be consistent...no idea what it means */ - DEBUG(5,("_reg_unknown_1a: Exit\n")); + DEBUG(5,("_reg_getversion: Exit\n")); return status; } @@ -593,82 +593,131 @@ done: WERROR _reg_shutdown(pipes_struct *p, REG_Q_SHUTDOWN *q_u, REG_R_SHUTDOWN *r_u) { - WERROR status = WERR_OK; + REG_Q_SHUTDOWN_EX q_u_ex; + REG_R_SHUTDOWN_EX r_u_ex; + + /* copy fields (including stealing memory) */ + + q_u_ex.server = q_u->server; + q_u_ex.message = q_u->message; + q_u_ex.timeout = q_u->timeout; + q_u_ex.force = q_u->force; + q_u_ex.reboot = q_u->reboot; + q_u_ex.reason = 0x0; /* don't care for now */ + + /* thunk down to _reg_shutdown_ex() (just returns a status) */ + + return _reg_shutdown_ex( p, &q_u_ex, &r_u_ex ); +} + +/******************************************************************* + reg_shutdown_ex + ********************************************************************/ + +#define SHUTDOWN_R_STRING "-r" +#define SHUTDOWN_F_STRING "-f" + + +WERROR _reg_shutdown_ex(pipes_struct *p, REG_Q_SHUTDOWN_EX *q_u, REG_R_SHUTDOWN_EX *r_u) +{ pstring shutdown_script; - UNISTR2 unimsg = q_u->uni_msg; pstring message; pstring chkmsg; fstring timeout; + fstring reason; fstring r; fstring f; + int ret; + BOOL can_shutdown; - /* message */ - rpcstr_pull (message, unimsg.buffer, sizeof(message), unimsg.uni_str_len*2,0); - /* security check */ + + pstrcpy(shutdown_script, lp_shutdown_script()); + + if ( !*shutdown_script ) + return WERR_ACCESS_DENIED; + + /* pull the message string and perform necessary sanity checks on it */ + + pstrcpy( message, "" ); + if ( q_u->message ) { + UNISTR2 *msg_string = q_u->message->string; + + rpcstr_pull( message, msg_string->buffer, sizeof(message), msg_string->uni_str_len*2, 0 ); + } alpha_strcpy (chkmsg, message, NULL, sizeof(message)); - /* timeout */ + fstr_sprintf(timeout, "%d", q_u->timeout); - /* reboot */ fstr_sprintf(r, (q_u->reboot) ? SHUTDOWN_R_STRING : ""); - /* force */ fstr_sprintf(f, (q_u->force) ? SHUTDOWN_F_STRING : ""); + fstr_sprintf( reason, "%d", q_u->reason ); - pstrcpy(shutdown_script, lp_shutdown_script()); - - if(*shutdown_script) { - int shutdown_ret; - SE_PRIV se_shutdown = SE_REMOTE_SHUTDOWN; - BOOL can_shutdown; + all_string_sub( shutdown_script, "%z", chkmsg, sizeof(shutdown_script) ); + all_string_sub( shutdown_script, "%t", timeout, sizeof(shutdown_script) ); + all_string_sub( shutdown_script, "%r", r, sizeof(shutdown_script) ); + all_string_sub( shutdown_script, "%f", f, sizeof(shutdown_script) ); + all_string_sub( shutdown_script, "%x", reason, sizeof(shutdown_script) ); - can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_shutdown ); + can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown ); /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/ - if ( can_shutdown ) + + /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root + Take the error return from the script and provide it as the Windows return code. */ + + if ( can_shutdown ) { + DEBUG(3,("_reg_shutdown_ex: Privilege Check is OK for shutdown \n")); become_root(); - all_string_sub(shutdown_script, "%m", chkmsg, sizeof(shutdown_script)); - all_string_sub(shutdown_script, "%t", timeout, sizeof(shutdown_script)); - all_string_sub(shutdown_script, "%r", r, sizeof(shutdown_script)); - all_string_sub(shutdown_script, "%f", f, sizeof(shutdown_script)); - shutdown_ret = smbrun(shutdown_script,NULL); - DEBUG(3,("_reg_shutdown: Running the command `%s' gave %d\n",shutdown_script,shutdown_ret)); + } + + ret = smbrun( shutdown_script, NULL ); + + DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n", + shutdown_script, ret)); + if ( can_shutdown ) unbecome_root(); + /********** END SeRemoteShutdownPrivilege BLOCK **********/ - } - return status; + return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED; } + + + /******************************************************************* reg_abort_shutdwon ********************************************************************/ WERROR _reg_abort_shutdown(pipes_struct *p, REG_Q_ABORT_SHUTDOWN *q_u, REG_R_ABORT_SHUTDOWN *r_u) { - WERROR status = WERR_OK; pstring abort_shutdown_script; + int ret; + BOOL can_shutdown; pstrcpy(abort_shutdown_script, lp_abort_shutdown_script()); - if(*abort_shutdown_script) { - int abort_shutdown_ret; - SE_PRIV se_shutdown = SE_REMOTE_SHUTDOWN; - BOOL can_shutdown; + if ( !*abort_shutdown_script ) + return WERR_ACCESS_DENIED; - can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_shutdown ); + can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown ); /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/ + if ( can_shutdown ) become_root(); - abort_shutdown_ret = smbrun(abort_shutdown_script,NULL); - DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",abort_shutdown_script,abort_shutdown_ret)); + + ret = smbrun( abort_shutdown_script, NULL ); + + DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n", + abort_shutdown_script, ret)); + if ( can_shutdown ) unbecome_root(); - /********** END SeRemoteShutdownPrivilege BLOCK **********/ - } + /********** END SeRemoteShutdownPrivilege BLOCK **********/ - return status; + return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED; } /******************************************************************* diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index 3c611be9ac..2e84a7b909 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/rpc_server/srv_spoolss_nt.c @@ -1491,10 +1491,10 @@ static void convert_to_openprinterex(TALLOC_CTX *ctx, SPOOL_Q_OPEN_PRINTER_EX *q DEBUG(8,("convert_to_openprinterex\n")); - q_u_ex->printername_ptr = q_u->printername_ptr; - - if (q_u->printername_ptr) - copy_unistr2(&q_u_ex->printername, &q_u->printername); + if ( q_u->printername ) { + q_u_ex->printername = TALLOC_P( ctx, UNISTR2 ); + copy_unistr2(q_u_ex->printername, q_u->printername); + } copy_printer_default(ctx, &q_u_ex->printer_default, &q_u->printer_default); } @@ -1588,7 +1588,6 @@ WERROR _spoolss_open_printer(pipes_struct *p, SPOOL_Q_OPEN_PRINTER *q_u, SPOOL_R WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, SPOOL_R_OPEN_PRINTER_EX *r_u) { - UNISTR2 *printername = NULL; PRINTER_DEFAULT *printer_default = &q_u->printer_default; POLICY_HND *handle = &r_u->handle; @@ -1597,15 +1596,13 @@ WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, struct current_user user; Printer_entry *Printer=NULL; - if (q_u->printername_ptr != 0) - printername = &q_u->printername; - - if (printername == NULL) + if ( !q_u->printername ) return WERR_INVALID_PRINTER_NAME; /* some sanity check because you can open a printer or a print server */ /* aka: \\server\printer or \\server */ - unistr2_to_ascii(name, printername, sizeof(name)-1); + + unistr2_to_ascii(name, q_u->printername, sizeof(name)-1); DEBUGADD(3,("checking name: %s\n",name)); @@ -7595,7 +7592,7 @@ static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_ WERROR _spoolss_addprinterex( pipes_struct *p, SPOOL_Q_ADDPRINTEREX *q_u, SPOOL_R_ADDPRINTEREX *r_u) { - UNISTR2 *uni_srv_name = &q_u->server_name; + UNISTR2 *uni_srv_name = q_u->server_name; uint32 level = q_u->level; SPOOL_PRINTER_INFO_LEVEL *info = &q_u->info; DEVICEMODE *devmode = q_u->devmode_ctr.devmode; diff --git a/source3/rpc_server/srv_svcctl.c b/source3/rpc_server/srv_svcctl.c new file mode 100644 index 0000000000..85fb9f9ce3 --- /dev/null +++ b/source3/rpc_server/srv_svcctl.c @@ -0,0 +1,294 @@ +/* + * 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_svcctl_close_service(pipes_struct *p) +{ + SVCCTL_Q_CLOSE_SERVICE q_u; + SVCCTL_R_CLOSE_SERVICE 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_close_service("", &q_u, data, 0)) + return False; + + r_u.status = _svcctl_close_service(p, &q_u, &r_u); + + if(!svcctl_io_r_close_service("", &r_u, rdata, 0)) + return False; + + return True; +} + +/******************************************************************* + ********************************************************************/ + +static BOOL api_svcctl_open_scmanager(pipes_struct *p) +{ + SVCCTL_Q_OPEN_SCMANAGER q_u; + SVCCTL_R_OPEN_SCMANAGER 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_open_scmanager("", &q_u, data, 0)) + return False; + + r_u.status = _svcctl_open_scmanager(p, &q_u, &r_u); + + if(!svcctl_io_r_open_scmanager("", &r_u, rdata, 0)) + return False; + + return True; +} + +/******************************************************************* + ********************************************************************/ + +static BOOL api_svcctl_open_service(pipes_struct *p) +{ + SVCCTL_Q_OPEN_SERVICE q_u; + SVCCTL_R_OPEN_SERVICE 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_open_service("", &q_u, data, 0)) + return False; + + r_u.status = _svcctl_open_service(p, &q_u, &r_u); + + if(!svcctl_io_r_open_service("", &r_u, rdata, 0)) + return False; + + return True; +} + +/******************************************************************* + ********************************************************************/ + +static BOOL api_svcctl_get_display_name(pipes_struct *p) +{ + SVCCTL_Q_GET_DISPLAY_NAME q_u; + SVCCTL_R_GET_DISPLAY_NAME 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_get_display_name("", &q_u, data, 0)) + return False; + + r_u.status = _svcctl_get_display_name(p, &q_u, &r_u); + + if(!svcctl_io_r_get_display_name("", &r_u, rdata, 0)) + return False; + + return True; +} + +/******************************************************************* + ********************************************************************/ + +static BOOL api_svcctl_query_status(pipes_struct *p) +{ + SVCCTL_Q_QUERY_STATUS q_u; + SVCCTL_R_QUERY_STATUS 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_query_status("", &q_u, data, 0)) + return False; + + r_u.status = _svcctl_query_status(p, &q_u, &r_u); + + if(!svcctl_io_r_query_status("", &r_u, rdata, 0)) + return False; + + return True; +} + +/******************************************************************* + ********************************************************************/ + +static BOOL api_svcctl_enum_services_status(pipes_struct *p) +{ + SVCCTL_Q_ENUM_SERVICES_STATUS q_u; + SVCCTL_R_ENUM_SERVICES_STATUS 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_enum_services_status("", &q_u, data, 0)) + return False; + + r_u.status = _svcctl_enum_services_status(p, &q_u, &r_u); + + if(!svcctl_io_r_enum_services_status("", &r_u, rdata, 0)) + return False; + + return True; +} + +/******************************************************************* + ********************************************************************/ + +static BOOL api_svcctl_enum_dependent_services(pipes_struct *p) +{ + SVCCTL_Q_ENUM_DEPENDENT_SERVICES q_u; + SVCCTL_R_ENUM_DEPENDENT_SERVICES 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_enum_dependent_services("", &q_u, data, 0)) + return False; + + r_u.status = _svcctl_enum_dependent_services(p, &q_u, &r_u); + + if(!svcctl_io_r_enum_dependent_services("", &r_u, rdata, 0)) + return False; + + return True; +} + +/******************************************************************* + ********************************************************************/ + +static BOOL api_svcctl_start_service(pipes_struct *p) +{ + SVCCTL_Q_START_SERVICE q_u; + SVCCTL_R_START_SERVICE 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_start_service("", &q_u, data, 0)) + return False; + + r_u.status = _svcctl_start_service(p, &q_u, &r_u); + + if(!svcctl_io_r_start_service("", &r_u, rdata, 0)) + return False; + + return True; +} + +/******************************************************************* + ********************************************************************/ + +static BOOL api_svcctl_control_service(pipes_struct *p) +{ + SVCCTL_Q_CONTROL_SERVICE q_u; + SVCCTL_R_CONTROL_SERVICE 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_control_service("", &q_u, data, 0)) + return False; + + r_u.status = _svcctl_control_service(p, &q_u, &r_u); + + if(!svcctl_io_r_control_service("", &r_u, rdata, 0)) + return False; + + return True; +} + +/******************************************************************* + ********************************************************************/ + +static BOOL api_svcctl_query_service_config(pipes_struct *p) +{ + SVCCTL_Q_QUERY_SERVICE_CONFIG q_u; + SVCCTL_R_QUERY_SERVICE_CONFIG 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_query_service_config("", &q_u, data, 0)) + return False; + + r_u.status = _svcctl_query_service_config(p, &q_u, &r_u); + + if(!svcctl_io_r_query_service_config("", &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_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 } +}; + +void svcctl_get_pipe_fns( struct api_struct **fns, int *n_fns ) +{ + *fns = api_svcctl_cmds; + *n_fns = sizeof(api_svcctl_cmds) / sizeof(struct api_struct); +} + +NTSTATUS rpc_svcctl_init(void) +{ + return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "svcctl", "ntsvcs", api_svcctl_cmds, + sizeof(api_svcctl_cmds) / sizeof(struct api_struct)); +} diff --git a/source3/rpc_server/srv_svcctl_nt.c b/source3/rpc_server/srv_svcctl_nt.c new file mode 100644 index 0000000000..19244d2208 --- /dev/null +++ b/source3/rpc_server/srv_svcctl_nt.c @@ -0,0 +1,291 @@ +/* + * 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 + +/* + * sertup the \PIPE\svcctl db API + */ + +static TDB_CONTEXT *svcctl_tdb; /* used for share security descriptors */ + +#define SCVCTL_DATABASE_VERSION_V1 1 + +/******************************************************************** +********************************************************************/ + +static BOOL init_svcctl_db( void ) +{ + static pid_t local_pid; + const char *vstring = "INFO/version"; + + /* see if we've already opened the tdb */ + + if (svcctl_tdb && local_pid == sys_getpid()) + return True; + + /* so open it */ + if ( !(svcctl_tdb = tdb_open_log(lock_path("svcctl.tdb"), 0, TDB_DEFAULT, + O_RDWR|O_CREAT, 0600))) + { + DEBUG(0,("Failed to open svcctl database %s (%s)\n", + lock_path("svcctl.tdb"), strerror(errno) )); + return False; + } + + local_pid = sys_getpid(); + + /***** BEGIN Check the tdb version ******/ + + tdb_lock_bystring(svcctl_tdb, vstring, 0); + + if ( tdb_fetch_int32(svcctl_tdb, vstring) != SCVCTL_DATABASE_VERSION_V1 ) + tdb_store_int32(svcctl_tdb, vstring, SCVCTL_DATABASE_VERSION_V1); + + tdb_unlock_bystring(svcctl_tdb, vstring); + + /***** END Check the tdb version ******/ + + return True; +} + +/******************************************************************** + TODO + (a) get and set security descriptors on services + (b) read and write QUERY_SERVICE_CONFIG structures + (c) create default secdesc objects for services and SCM + (d) check access control masks with se_access_check() + (e) implement SERVICE * for associating with open handles +********************************************************************/ + +/******************************************************************** +********************************************************************/ + +WERROR _svcctl_open_scmanager(pipes_struct *p, SVCCTL_Q_OPEN_SCMANAGER *q_u, SVCCTL_R_OPEN_SCMANAGER *r_u) +{ + /* just fake it for now */ + + if ( !create_policy_hnd( p, &r_u->handle, NULL, NULL ) ) + return WERR_ACCESS_DENIED; + + return WERR_OK; +} + +/******************************************************************** +********************************************************************/ + +WERROR _svcctl_open_service(pipes_struct *p, SVCCTL_Q_OPEN_SERVICE *q_u, SVCCTL_R_OPEN_SERVICE *r_u) +{ + fstring service; + + rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0); + + /* can only be called on service name (not displayname) */ + + if ( !(strequal( service, "NETLOGON") || strequal(service, "Spooler")) ) + return WERR_NO_SUCH_SERVICE; + + if ( !create_policy_hnd( p, &r_u->handle, NULL, NULL ) ) + return WERR_ACCESS_DENIED; + + return WERR_OK; +} + +/******************************************************************** +********************************************************************/ + +WERROR _svcctl_close_service(pipes_struct *p, SVCCTL_Q_CLOSE_SERVICE *q_u, SVCCTL_R_CLOSE_SERVICE *r_u) +{ + if ( !close_policy_hnd( p, &q_u->handle ) ) + return WERR_BADFID; + + return WERR_OK; +} + +/******************************************************************** +********************************************************************/ + +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; + + rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0); + + DEBUG(10,("_svcctl_get_display_name: service name [%s]\n", service)); + + if ( !strequal( service, "NETLOGON" ) ) + return WERR_ACCESS_DENIED; + + fstrcpy( displayname, "Net Logon"); + init_svcctl_r_get_display_name( r_u, displayname ); + + return WERR_OK; +} + +/******************************************************************** +********************************************************************/ + +WERROR _svcctl_query_status(pipes_struct *p, SVCCTL_Q_QUERY_STATUS *q_u, SVCCTL_R_QUERY_STATUS *r_u) +{ + + r_u->svc_status.type = 0x0110; + r_u->svc_status.state = 0x0004; + r_u->svc_status.controls_accepted = 0x0005; + + return WERR_OK; +} + +/******************************************************************** +********************************************************************/ + +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_services = 0; + int i = 0; + size_t buffer_size; + WERROR result = WERR_OK; + + /* num_services = str_list_count( lp_enable_svcctl() ); */ + num_services = 2; + + if ( !(services = TALLOC_ARRAY( p->mem_ctx, ENUM_SERVICES_STATUS, num_services )) ) + return WERR_NOMEM; + + DEBUG(8,("_svcctl_enum_services_status: Enumerating %d services\n", num_services)); + + init_unistr( &services[i].servicename, "Spooler" ); + init_unistr( &services[i].displayname, "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" ); + + 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; + + buffer_size = 0; + for (i=0; i q_u->buffer_size ) { + num_services = 0; + result = WERR_MORE_DATA; + } + + /* we have to set the outgoing buffer size to the same as the + incoming buffer size (even in the case of failure */ + + rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx ); + + if ( W_ERROR_IS_OK(result) ) { + for ( i=0; ibuffer, 0 ); + } + + r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size; + r_u->returned = num_services; + + if ( !(r_u->resume = TALLOC_P( p->mem_ctx, uint32 )) ) + return WERR_NOMEM; + + *r_u->resume = 0x0; + + return result; +} + +/******************************************************************** +********************************************************************/ + +WERROR _svcctl_start_service(pipes_struct *p, SVCCTL_Q_START_SERVICE *q_u, SVCCTL_R_START_SERVICE *r_u) +{ + return WERR_ACCESS_DENIED; +} + +/******************************************************************** +********************************************************************/ + +WERROR _svcctl_control_service(pipes_struct *p, SVCCTL_Q_CONTROL_SERVICE *q_u, SVCCTL_R_CONTROL_SERVICE *r_u) +{ + return WERR_ACCESS_DENIED; +} + +/******************************************************************** +********************************************************************/ + +WERROR _svcctl_enum_dependent_services( pipes_struct *p, SVCCTL_Q_ENUM_DEPENDENT_SERVICES *q_u, SVCCTL_R_ENUM_DEPENDENT_SERVICES *r_u ) +{ + + /* we have to set the outgoing buffer size to the same as the + 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; + + /* no dependent services...basically a stub function */ + r_u->returned = 0; + + return WERR_OK; +} + +/******************************************************************** +********************************************************************/ + +WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u ) +{ + + /* 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; + + /* no dependent services...basically a stub function */ + + return WERR_ACCESS_DENIED; +} + + -- cgit