mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
0baae61e42
Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Martin Schwenke <mschwenke@ddn.com>
921 lines
20 KiB
C
921 lines
20 KiB
C
/*
|
|
* Unix SMB/CIFS implementation.
|
|
*
|
|
* Window Search Service
|
|
*
|
|
* Copyright (c) Noel Power
|
|
*
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "includes.h"
|
|
#include "lib/util/util_file.h"
|
|
#include "librpc/wsp/wsp_util.h"
|
|
#include "librpc/gen_ndr/wsp.h"
|
|
#include "librpc/gen_ndr/ndr_wsp.h"
|
|
#include "lib/util/strv_util.h"
|
|
#include "lib/util/strv.h"
|
|
#include "lib/util/util_str_hex.h"
|
|
#include "source3/param/param_proto.h"
|
|
#include "lib/util/dlinklist.h"
|
|
|
|
#define BUFFER_SIZE 1024000
|
|
struct guidtopropmap_holder
|
|
{
|
|
struct guidtopropmap *guidtopropmaploc;
|
|
};
|
|
|
|
struct full_propset_info_list {
|
|
struct full_propset_info_list *prev, *next;
|
|
struct full_propset_info info;
|
|
};
|
|
|
|
struct guidtopropmap {
|
|
struct guidtopropmap *prev, *next;
|
|
struct GUID guid;
|
|
struct full_propset_info_list *propset;
|
|
};
|
|
|
|
static struct guidtopropmap *find_guid_props(
|
|
struct guidtopropmap_holder *holder,
|
|
const struct GUID *guid)
|
|
{
|
|
struct guidtopropmap *mapitem;
|
|
for (mapitem = holder->guidtopropmaploc; mapitem; mapitem = mapitem->next) {
|
|
if (GUID_equal(guid, &mapitem->guid)) {
|
|
return mapitem;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static bool getbool(char *str)
|
|
{
|
|
char *cpy = talloc_strdup(NULL, str);
|
|
bool result;
|
|
|
|
trim_string(cpy, " ", " ");
|
|
if (strequal("TRUE", cpy)) {
|
|
result = true;
|
|
} else {
|
|
result = false;
|
|
}
|
|
TALLOC_FREE(cpy);
|
|
return result;
|
|
}
|
|
|
|
struct {
|
|
const char* typename;
|
|
uint16_t type;
|
|
} vtype_map[] = {
|
|
{"GUID", VT_CLSID},
|
|
{"String", VT_LPWSTR},
|
|
{"BString", VT_BSTR},
|
|
{"Double", VT_R8},
|
|
{"Buffer", VT_BLOB_OBJECT},
|
|
{"Byte", VT_UI1},
|
|
{"UInt64", VT_UI8},
|
|
{"Int64", VT_I8},
|
|
{"UInt32", VT_UI4},
|
|
{"Int32", VT_I4},
|
|
{"UInt16", VT_UI2},
|
|
{"Int16", VT_I2},
|
|
{"DateTime", VT_FILETIME},
|
|
{"Boolean", VT_BOOL}
|
|
};
|
|
|
|
static uint16_t getvtype(char *str, bool isvec)
|
|
{
|
|
uint16_t result = UINT16_MAX;
|
|
int i;
|
|
for (i = 0; i < ARRAY_SIZE(vtype_map); i++) {
|
|
if (strequal(vtype_map[i].typename, str)) {
|
|
result = vtype_map[i].type;
|
|
if (isvec) {
|
|
result |= VT_VECTOR;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static bool parse_csv_line(TALLOC_CTX *ctx,
|
|
char **csvs, size_t num_values,
|
|
struct guidtopropmap_holder *propmap_holder)
|
|
{
|
|
struct guidtopropmap *mapitem = NULL;
|
|
struct full_propset_info_list *item = NULL;
|
|
|
|
char *guid_str = NULL;
|
|
struct GUID guid;
|
|
bool ok;
|
|
|
|
item = talloc_zero(ctx,
|
|
struct full_propset_info_list);
|
|
if (!item) {
|
|
return false;
|
|
}
|
|
|
|
item->info.in_inverted_index = false;
|
|
item->info.is_column = true;
|
|
item->info.can_col_be_indexed = true;
|
|
|
|
if (strlen(csvs[1])) {
|
|
guid_str = talloc_strdup(ctx, csvs[1]);
|
|
}
|
|
|
|
if (!guid_str) {
|
|
DBG_ERR("out of memory\n");
|
|
return false;
|
|
}
|
|
|
|
if (!trim_string(guid_str, "{", "}")) {
|
|
return false;
|
|
}
|
|
|
|
if (strlen(csvs[0])) {
|
|
char *tmp = talloc_strdup(item, csvs[0]);
|
|
trim_string(tmp, " ", " ");
|
|
item->info.name = tmp;
|
|
}
|
|
|
|
if (strlen(csvs[2])) {
|
|
item->info.id = atoi(csvs[2]);
|
|
}
|
|
|
|
if (strlen(csvs[3])) {
|
|
item->info.in_inverted_index = getbool(csvs[3]);
|
|
}
|
|
|
|
if (strlen(csvs[4])) {
|
|
item->info.is_column = getbool(csvs[4]);
|
|
}
|
|
|
|
if (strlen(csvs[5])) {
|
|
item->info.can_col_be_indexed = getbool(csvs[5]);
|
|
}
|
|
|
|
if (strlen(csvs[6])) {
|
|
bool isvec = false;
|
|
uint16_t type;
|
|
if (strlen(csvs[0])) {
|
|
isvec = getbool(csvs[8]);
|
|
}
|
|
type = getvtype(csvs[6], isvec);
|
|
if (type == UINT16_MAX) {
|
|
DBG_ERR("failed to parse type\n");
|
|
return false;
|
|
}
|
|
item->info.vtype = type;
|
|
}
|
|
|
|
ok = parse_guid_string(guid_str, &guid);
|
|
if (!ok) {
|
|
return false;
|
|
}
|
|
|
|
mapitem = find_guid_props(propmap_holder, &guid);
|
|
if (!mapitem) {
|
|
mapitem = talloc_zero(propmap_holder,
|
|
struct guidtopropmap);
|
|
if (!mapitem) {
|
|
return false;
|
|
}
|
|
mapitem->guid = guid;
|
|
DLIST_ADD_END(propmap_holder->guidtopropmaploc, mapitem);
|
|
}
|
|
|
|
talloc_steal(mapitem, item);
|
|
DLIST_ADD_END(mapitem->propset, item);
|
|
return true;
|
|
}
|
|
|
|
static bool parse_properties_line(TALLOC_CTX *ctx,
|
|
const char* line,
|
|
struct guidtopropmap_holder *propmap_holder)
|
|
{
|
|
int ret;
|
|
int pos;
|
|
char* strv = NULL;
|
|
char** csv_line = NULL;
|
|
char* t = NULL;
|
|
size_t len;
|
|
|
|
ret = strv_split(ctx,
|
|
&strv,
|
|
line,
|
|
",");
|
|
|
|
if (ret != 0) {
|
|
DBG_ERR("failed to split line\n");
|
|
return false;
|
|
}
|
|
|
|
len = strv_count(strv);
|
|
|
|
if (len < 9) {
|
|
DBG_WARNING("skipping line as it doesn't have "
|
|
"enough fields\n");
|
|
return true;
|
|
}
|
|
|
|
csv_line = talloc_zero_array(ctx,
|
|
char *,
|
|
len);
|
|
|
|
if (!csv_line) {
|
|
DBG_ERR("out of memory\n");
|
|
return false;
|
|
}
|
|
for (pos = 0; pos < talloc_array_length(csv_line); pos++) {
|
|
t = strv_next(strv, t);
|
|
/* the scraped property file can have a non ascii char */
|
|
if (strlen(t) == 1 && *t == 0xa0) {
|
|
csv_line[pos] = talloc_strdup(csv_line,
|
|
"");
|
|
} else {
|
|
csv_line[pos] = talloc_strdup(csv_line,
|
|
t);
|
|
}
|
|
trim_string(csv_line[pos], " ", " ");
|
|
}
|
|
|
|
if (!parse_csv_line(csv_line, csv_line, len, propmap_holder)) {
|
|
DBG_ERR("failed to parse line\n");
|
|
TALLOC_FREE(csv_line);
|
|
return false;
|
|
}
|
|
TALLOC_FREE(csv_line);
|
|
return true;
|
|
}
|
|
|
|
static bool parse_properties_csvfile(TALLOC_CTX *ctx,
|
|
struct guidtopropmap_holder *propmap_holder,
|
|
const char* filename)
|
|
{
|
|
char **lines = NULL;
|
|
int numlines;
|
|
int i;
|
|
|
|
if (filename == NULL || strlen(filename) == 0) {
|
|
return false;
|
|
}
|
|
|
|
lines = file_lines_load(filename,
|
|
&numlines,
|
|
BUFFER_SIZE,
|
|
ctx);
|
|
if (!lines) {
|
|
DBG_ERR("Failed to load %s\n", filename);
|
|
return false;
|
|
}
|
|
DBG_ERR("parsed %d lines\n", numlines);
|
|
|
|
for (i = 0; i < numlines; i++) {
|
|
TALLOC_CTX *line_ctx = talloc_init("line context");
|
|
if (!line_ctx) {
|
|
DBG_ERR("out of memory\n");
|
|
return false;
|
|
}
|
|
|
|
trim_string(lines[i], " ", " ");
|
|
if (lines[i][0] == '#') {
|
|
DBG_WARNING("skipping comment at line %d.\n)", i);
|
|
TALLOC_FREE(line_ctx);
|
|
continue;
|
|
}
|
|
|
|
if (!parse_properties_line(line_ctx,
|
|
lines[i],
|
|
propmap_holder)) {
|
|
DBG_ERR("Failed to parse line %d\n", i);
|
|
}
|
|
TALLOC_FREE(line_ctx);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool populate_map(struct guidtopropmap_holder *propmap_holder)
|
|
{
|
|
const char * path = NULL;
|
|
path = lp_wsp_property_file();
|
|
|
|
/* first populate the map from property file */
|
|
if (path) {
|
|
parse_properties_csvfile(propmap_holder, propmap_holder, path);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static struct guidtopropmap_holder *propmap(void)
|
|
{
|
|
static struct guidtopropmap_holder *holder = NULL;
|
|
|
|
if (!holder) {
|
|
holder = talloc_zero(NULL, struct guidtopropmap_holder);
|
|
if (holder) {
|
|
populate_map(holder);
|
|
}
|
|
}
|
|
|
|
return holder;
|
|
}
|
|
|
|
const struct full_propset_info *get_propset_info_with_guid(
|
|
const char *prop_name,
|
|
struct GUID *propset_guid)
|
|
{
|
|
const struct full_propset_info *result = NULL;
|
|
struct guidtopropmap_holder *holder = NULL;
|
|
struct guidtopropmap *mapitem = NULL;
|
|
|
|
size_t i;
|
|
const struct full_guid_propset *guid_propset = NULL;
|
|
|
|
/* search builtin props first */
|
|
for (i = 0; full_propertyset[i].prop_info != NULL; i++) {
|
|
const struct full_propset_info *item = NULL;
|
|
guid_propset = &full_propertyset[i];
|
|
item = guid_propset->prop_info;
|
|
while (item->id) {
|
|
if (strequal(prop_name, item->name)) {
|
|
*propset_guid = guid_propset->guid;
|
|
result = item;
|
|
break;
|
|
}
|
|
item++;
|
|
}
|
|
if (result) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
return result;
|
|
}
|
|
|
|
/* if we didn't find a match in builtin props try the extra props */
|
|
holder = propmap();
|
|
for (mapitem = holder->guidtopropmaploc; mapitem;
|
|
mapitem = mapitem->next) {
|
|
struct full_propset_info_list *propitem;
|
|
for (propitem = mapitem->propset; propitem;
|
|
propitem = propitem->next) {
|
|
if (strequal(prop_name, propitem->info.name)) {
|
|
*propset_guid = mapitem->guid;
|
|
result = &propitem->info;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const struct full_propset_info *get_prop_info(const char *prop_name)
|
|
{
|
|
const struct full_propset_info *result = NULL;
|
|
struct GUID guid;
|
|
result = get_propset_info_with_guid(prop_name, &guid);
|
|
return result;
|
|
}
|
|
|
|
char *prop_from_fullprop(TALLOC_CTX *ctx, struct wsp_cfullpropspec *fullprop)
|
|
{
|
|
size_t i;
|
|
char *result = NULL;
|
|
const struct full_propset_info *item = NULL;
|
|
const struct full_propset_info_list *prop_item = NULL;
|
|
bool search_by_id = (fullprop->ulkind == PRSPEC_PROPID);
|
|
struct guidtopropmap_holder *holder = NULL;
|
|
struct guidtopropmap *mapitem = NULL;
|
|
|
|
/* check builtin properties */
|
|
for (i = 0; full_propertyset[i].prop_info != NULL; i++) {
|
|
/* find propset */
|
|
if (GUID_equal(&fullprop->guidpropset,
|
|
&full_propertyset[i].guid)) {
|
|
item = full_propertyset[i].prop_info;
|
|
break;
|
|
}
|
|
}
|
|
if (item) {
|
|
while (item->id) {
|
|
if (search_by_id) {
|
|
if( fullprop->name_or_id.prspec == item->id) {
|
|
result = talloc_strdup(ctx, item->name);
|
|
break;
|
|
}
|
|
} else if (strcmp(item->name,
|
|
fullprop->name_or_id.propname.vstring)
|
|
== 0) {
|
|
result = talloc_strdup(ctx, item->name);
|
|
break;
|
|
}
|
|
item++;
|
|
}
|
|
}
|
|
|
|
/* not found, search the extra props */
|
|
if (!result) {
|
|
holder = propmap();
|
|
|
|
for (mapitem = holder->guidtopropmaploc; mapitem;
|
|
mapitem = mapitem->next) {
|
|
if (GUID_equal(&fullprop->guidpropset,
|
|
&mapitem->guid)) {
|
|
prop_item = mapitem->propset;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (;prop_item; prop_item = prop_item->next) {
|
|
if (search_by_id) {
|
|
if(fullprop->name_or_id.prspec ==
|
|
prop_item->info.id) {
|
|
result = talloc_strdup(ctx,
|
|
prop_item->info.name);
|
|
break;
|
|
}
|
|
} else if (strcmp(prop_item->info.name,
|
|
fullprop->name_or_id.propname.vstring) == 0) {
|
|
result = talloc_strdup(ctx,
|
|
prop_item->info.name);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!result) {
|
|
result = GUID_string(ctx, &fullprop->guidpropset);
|
|
|
|
if (search_by_id) {
|
|
result = talloc_asprintf(result, "%s/%d", result,
|
|
fullprop->name_or_id.prspec);
|
|
} else {
|
|
result = talloc_asprintf(result, "%s/%s", result,
|
|
fullprop->name_or_id.propname.vstring);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const char *genmeth_to_string(uint32_t genmethod)
|
|
{
|
|
const char *result = NULL;
|
|
switch (genmethod) {
|
|
case 0:
|
|
result = "equals";
|
|
break;
|
|
case 1:
|
|
result = "starts with";
|
|
break;
|
|
case 2:
|
|
result = "matches inflection";
|
|
break;
|
|
default:
|
|
result = NULL;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool is_operator(struct wsp_crestriction *restriction) {
|
|
bool result;
|
|
switch(restriction->ultype) {
|
|
case RTAND:
|
|
case RTOR:
|
|
case RTNOT:
|
|
result = true;
|
|
break;
|
|
default:
|
|
result = false;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const char *op_as_string(struct wsp_crestriction *restriction)
|
|
{
|
|
const char *op = NULL;
|
|
if (is_operator(restriction)) {
|
|
switch(restriction->ultype) {
|
|
case RTAND:
|
|
op = " && ";
|
|
break;
|
|
case RTOR:
|
|
op = " || ";
|
|
break;
|
|
case RTNOT:
|
|
op = "!";
|
|
break;
|
|
}
|
|
} else if (restriction->ultype == RTPROPERTY) {
|
|
struct wsp_cpropertyrestriction *prop_restr =
|
|
&restriction->restriction.cpropertyrestriction;
|
|
switch (prop_restr->relop & 0XF) {
|
|
case PREQ:
|
|
op = "=";
|
|
break;
|
|
case PRNE:
|
|
op = "!=";
|
|
break;
|
|
case PRGE:
|
|
op = ">=";
|
|
break;
|
|
case PRLE:
|
|
op = "<=";
|
|
break;
|
|
case PRLT:
|
|
op = "<";
|
|
break;
|
|
case PRGT:
|
|
op = ">";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (restriction->ultype == RTCONTENT) {
|
|
struct wsp_ccontentrestriction *content = NULL;
|
|
content = &restriction->restriction.ccontentrestriction;
|
|
op = genmeth_to_string(content->ulgeneratemethod);
|
|
} else if (restriction->ultype == RTNATLANGUAGE) {
|
|
op = "=";
|
|
}
|
|
return op;
|
|
}
|
|
|
|
struct wsp_cfullpropspec *get_full_prop(struct wsp_crestriction *restriction)
|
|
{
|
|
struct wsp_cfullpropspec *result;
|
|
switch (restriction->ultype) {
|
|
case RTPROPERTY:
|
|
result = &restriction->restriction.cpropertyrestriction.property;
|
|
break;
|
|
case RTCONTENT:
|
|
result = &restriction->restriction.ccontentrestriction.property;
|
|
break;
|
|
case RTNATLANGUAGE:
|
|
result = &restriction->restriction.cnatlanguagerestriction.property;
|
|
break;
|
|
default:
|
|
result = NULL;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const char *variant_as_string(TALLOC_CTX *ctx,
|
|
struct wsp_cbasestoragevariant *value, bool quote)
|
|
{
|
|
const char* result = NULL;
|
|
switch(value->vtype) {
|
|
case VT_UI1:
|
|
result = talloc_asprintf(ctx, "%u",
|
|
value->vvalue.vt_ui1);
|
|
break;
|
|
case VT_INT:
|
|
case VT_I4:
|
|
result = talloc_asprintf(ctx, "%d",
|
|
value->vvalue.vt_i4);
|
|
break;
|
|
case VT_ERROR:
|
|
case VT_UINT:
|
|
case VT_UI4:
|
|
result = talloc_asprintf(ctx, "%u",
|
|
value->vvalue.vt_ui4);
|
|
break;
|
|
case VT_UI2:
|
|
case VT_I2:
|
|
result = talloc_asprintf(ctx, "%u",
|
|
value->vvalue.vt_ui2);
|
|
break;
|
|
case VT_BOOL:
|
|
result = talloc_asprintf(ctx, "%s",
|
|
value->vvalue.vt_ui2 == 0xFFFF ?
|
|
"true" : "false");
|
|
break;
|
|
case VT_DATE:
|
|
case VT_FILETIME: {
|
|
NTTIME filetime = value->vvalue.vt_ui8;
|
|
time_t unixtime;
|
|
struct tm *tm = NULL;
|
|
char datestring[256];
|
|
unixtime = nt_time_to_unix(filetime);
|
|
tm = gmtime(&unixtime);
|
|
strftime(datestring, sizeof(datestring), "%FT%TZ", tm);
|
|
result = talloc_strdup(ctx, datestring);
|
|
break;
|
|
}
|
|
case VT_R4: {
|
|
float f;
|
|
if (sizeof(f) != sizeof(value->vvalue.vt_ui4)) {
|
|
DBG_ERR("can't convert float\n");
|
|
break;
|
|
}
|
|
memcpy((void*)&f,
|
|
(void*)&value->vvalue.vt_ui4,
|
|
sizeof(value->vvalue.vt_ui4));
|
|
result = talloc_asprintf(ctx, "%f",
|
|
f);
|
|
break;
|
|
}
|
|
case VT_R8: {
|
|
/* should this really be unsigned ? */
|
|
double dval;
|
|
if (sizeof(dval) != sizeof(value->vvalue.vt_i8)) {
|
|
DBG_ERR("can't convert double\n");
|
|
break;
|
|
}
|
|
memcpy((void*)&dval,
|
|
(void*)&value->vvalue.vt_i8,
|
|
sizeof(dval));
|
|
result = talloc_asprintf(ctx, "%f",
|
|
dval);
|
|
break;
|
|
}
|
|
case VT_I8: {
|
|
result = talloc_asprintf(ctx, "%" PRIi64,
|
|
value->vvalue.vt_i8);
|
|
break;
|
|
}
|
|
case VT_UI8: {
|
|
result = talloc_asprintf(ctx, "%" PRIu64,
|
|
value->vvalue.vt_ui8);
|
|
break;
|
|
}
|
|
case VT_LPWSTR:
|
|
result = talloc_asprintf(ctx, "%s%s%s",
|
|
quote ? "\'" : "",
|
|
value->vvalue.vt_lpwstr.value,
|
|
quote ? "\'" : "");
|
|
break;
|
|
case VT_LPWSTR | VT_VECTOR: {
|
|
int num_elems =
|
|
value->vvalue.vt_lpwstr_v.vvector_elements;
|
|
int i;
|
|
for(i = 0; i < num_elems; i++) {
|
|
struct vt_lpwstr_vec *vec;
|
|
const char *val;
|
|
vec = &value->vvalue.vt_lpwstr_v;
|
|
val = vec->vvector_data[i].value;
|
|
result =
|
|
talloc_asprintf(ctx,
|
|
"%s%s%s%s%s",
|
|
result ? result : "",
|
|
i ? "," : "",
|
|
quote ? "\'" : "",
|
|
val,
|
|
quote ? "\'" : "");
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
DBG_INFO("can't represent unsupported vtype 0x%x as string\n",
|
|
value->vtype);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static const struct {
|
|
uint32_t id;
|
|
const char *name;
|
|
} typename_map[] = {
|
|
{VT_EMPTY, "Empty"},
|
|
{VT_NULL, "Null"},
|
|
{VT_I2, "VT_I2"},
|
|
{VT_I4, "VT_I4"},
|
|
{VT_I4, "VT_I4"},
|
|
{VT_R4, "VT_R4"},
|
|
{VT_R8, "VT_R8"},
|
|
{VT_CY, "VT_CY"},
|
|
{VT_DATE, "VT_DATE"},
|
|
{VT_BSTR, "VT_BSTR"},
|
|
{VT_I1, "VT_I1"},
|
|
{VT_UI1, "VT_UI1"},
|
|
{VT_UI2, "VT_UI2"},
|
|
{VT_UI4, "VT_UI4"},
|
|
{VT_I8, "VT_I8"},
|
|
{VT_UI8, "VT_UI8"},
|
|
{VT_INT, "VT_INT"},
|
|
{VT_UINT, "VT_UINT"},
|
|
{VT_ERROR, "VT_ERROR"},
|
|
{VT_BOOL, "VT_BOOL"},
|
|
{VT_VARIANT, "VT_VARIANT"},
|
|
{VT_DECIMAL, "VT_DECIMAL"},
|
|
{VT_FILETIME, "VT_FILETIME"},
|
|
{VT_BLOB, "VT_BLOB"},
|
|
{VT_BLOB_OBJECT, "VT_BLOB_OBJECT"},
|
|
{VT_CLSID, "VT_CLSID"},
|
|
{VT_LPSTR, "VT_LPSTR"},
|
|
{VT_LPWSTR, "VT_LPWSTR"},
|
|
{VT_COMPRESSED_LPWSTR, "VT_COMPRESSED_LPWSTR"},
|
|
};
|
|
|
|
const char *get_vtype_name(uint32_t type)
|
|
{
|
|
const char *type_name = NULL;
|
|
static char result_buf[255];
|
|
int i;
|
|
uint32_t temp = type & ~(VT_VECTOR | VT_ARRAY);
|
|
for (i = 0; i < ARRAY_SIZE(typename_map); i++) {
|
|
if (temp == typename_map[i].id) {
|
|
type_name = typename_map[i].name;
|
|
break;
|
|
}
|
|
}
|
|
if (type & VT_VECTOR) {
|
|
snprintf(result_buf, sizeof(result_buf), "Vector | %s", type_name);
|
|
} else if (type & VT_ARRAY) {
|
|
snprintf(result_buf, sizeof(result_buf), "Array | %s", type_name);
|
|
} else {
|
|
snprintf(result_buf, sizeof(result_buf), "%s", type_name);
|
|
}
|
|
return result_buf;
|
|
}
|
|
|
|
bool is_variable_size(uint16_t vtype)
|
|
{
|
|
bool result;
|
|
switch(vtype) {
|
|
case VT_LPWSTR:
|
|
case VT_COMPRESSED_LPWSTR:
|
|
case VT_BSTR:
|
|
case VT_BLOB:
|
|
case VT_BLOB_OBJECT:
|
|
case VT_VARIANT:
|
|
result = true;
|
|
break;
|
|
default:
|
|
result = false;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const char *get_store_status(uint8_t status_byte)
|
|
{
|
|
const char *result;
|
|
switch(status_byte) {
|
|
case 0:
|
|
result = "StoreStatusOk";
|
|
break;
|
|
case 1:
|
|
result = "StoreStatusDeferred";
|
|
break;
|
|
case 2:
|
|
result = "StoreStatusNull";
|
|
break;
|
|
default:
|
|
result = "Unknown Status";
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void set_variant_lpwstr(TALLOC_CTX *ctx,
|
|
struct wsp_cbasestoragevariant *vvalue,
|
|
const char *string_val)
|
|
{
|
|
vvalue->vtype = VT_LPWSTR;
|
|
vvalue->vvalue.vt_lpwstr.value = talloc_strdup(ctx, string_val);
|
|
}
|
|
|
|
void set_variant_i4(TALLOC_CTX *ctx,
|
|
struct wsp_cbasestoragevariant *vvalue,
|
|
uint32_t val)
|
|
{
|
|
vvalue->vtype = VT_I4;
|
|
vvalue->vvalue.vt_i4 = val;
|
|
}
|
|
|
|
void set_variant_vt_bool(TALLOC_CTX *ctx,
|
|
struct wsp_cbasestoragevariant *variant,
|
|
bool bval)
|
|
{
|
|
variant->vtype = VT_BOOL;
|
|
variant->vvalue.vt_bool = bval;
|
|
}
|
|
|
|
static void fill_int32_vec(TALLOC_CTX* ctx,
|
|
int32_t **pdest,
|
|
int32_t* ivector, uint32_t elems)
|
|
{
|
|
int i;
|
|
int32_t *dest = talloc_zero_array(ctx, int32_t, elems);
|
|
for ( i = 0; i < elems; i++ ) {
|
|
dest[ i ] = ivector[ i ];
|
|
}
|
|
*pdest = dest;
|
|
}
|
|
|
|
void set_variant_i4_vector(TALLOC_CTX *ctx,
|
|
struct wsp_cbasestoragevariant *variant,
|
|
int32_t* ivector, uint32_t elems)
|
|
{
|
|
variant->vtype = VT_VECTOR | VT_I4;
|
|
variant->vvalue.vt_i4_vec.vvector_elements = elems;
|
|
fill_int32_vec(ctx, &variant->vvalue.vt_i4_vec.vvector_data, ivector, elems);
|
|
}
|
|
|
|
static void fill_string_vec(TALLOC_CTX* ctx,
|
|
struct wsp_cbasestoragevariant *variant,
|
|
const char **strings, uint16_t elems)
|
|
{
|
|
int i;
|
|
variant->vvalue.vt_lpwstr_v.vvector_elements = elems;
|
|
variant->vvalue.vt_lpwstr_v.vvector_data = talloc_zero_array(ctx,
|
|
struct vt_lpwstr,
|
|
elems);
|
|
|
|
for( i = 0; i < elems; i++ ) {
|
|
variant->vvalue.vt_lpwstr_v.vvector_data[ i ].value = talloc_strdup(ctx, strings[ i ]);
|
|
}
|
|
}
|
|
|
|
static void fill_bstr_vec(TALLOC_CTX *ctx,
|
|
struct vt_bstr **pvector,
|
|
const char **strings, uint16_t elems)
|
|
{
|
|
int i;
|
|
struct vt_bstr *vdata = talloc_zero_array(ctx, struct vt_bstr, elems);
|
|
|
|
for( i = 0; i < elems; i++ ) {
|
|
vdata [ i ].value = talloc_strdup(ctx, strings[ i ]);
|
|
}
|
|
*pvector = vdata;
|
|
}
|
|
|
|
void set_variant_bstr(TALLOC_CTX *ctx, struct wsp_cbasestoragevariant *variant,
|
|
const char *string_val)
|
|
{
|
|
variant->vtype = VT_BSTR;
|
|
variant->vvalue.vt_bstr.value = talloc_strdup(ctx, string_val);
|
|
}
|
|
|
|
void set_variant_lpwstr_vector(TALLOC_CTX *ctx,
|
|
struct wsp_cbasestoragevariant *variant,
|
|
const char **string_vals, uint32_t elems)
|
|
{
|
|
variant->vtype = VT_LPWSTR | VT_VECTOR;
|
|
fill_string_vec(ctx, variant, string_vals, elems);
|
|
}
|
|
|
|
void set_variant_array_bstr(TALLOC_CTX *ctx,
|
|
struct wsp_cbasestoragevariant *variant,
|
|
const char **string_vals, uint16_t elems)
|
|
{
|
|
variant->vtype = VT_BSTR | VT_ARRAY;
|
|
variant->vvalue.vt_bstr_array.cdims = 1;
|
|
variant->vvalue.vt_bstr_array.ffeatures = 0;
|
|
|
|
variant->vvalue.vt_bstr_array.rgsabound =
|
|
talloc_zero_array(ctx, struct safearraybound, 1);
|
|
|
|
variant->vvalue.vt_bstr_array.rgsabound[0].celements = elems;
|
|
variant->vvalue.vt_bstr_array.rgsabound[0].ilbound = 0;
|
|
variant->vvalue.vt_bstr_array.cbelements = 0;
|
|
fill_bstr_vec(ctx, &variant->vvalue.vt_bstr_array.vdata,
|
|
string_vals, elems);
|
|
/*
|
|
* if cbelements is the num bytes per elem it kindof means each
|
|
* string in the array must be the same size ?
|
|
*/
|
|
|
|
if (elems >0) {
|
|
variant->vvalue.vt_bstr_array.cbelements =
|
|
strlen_m_term(variant->vvalue.vt_bstr_array.vdata[0].value)*2;
|
|
}
|
|
}
|
|
|
|
/* create single dim array of vt_i4 */
|
|
void set_variant_array_i4(TALLOC_CTX *ctx,
|
|
struct wsp_cbasestoragevariant *variant,
|
|
int32_t *vals, uint16_t elems)
|
|
{
|
|
/* #TODO see if we can combine with other set_variant_array methods */
|
|
variant->vtype = VT_I4 | VT_ARRAY;
|
|
variant->vvalue.vt_i4_array.cdims = 1;
|
|
variant->vvalue.vt_i4_array.ffeatures = 0;
|
|
|
|
variant->vvalue.vt_i4_array.rgsabound =
|
|
talloc_zero_array(ctx, struct safearraybound, 1);
|
|
|
|
variant->vvalue.vt_i4_array.rgsabound[0].celements = elems;
|
|
variant->vvalue.vt_i4_array.rgsabound[0].ilbound = 0;
|
|
variant->vvalue.vt_i4_array.cbelements = sizeof(uint32_t);
|
|
fill_int32_vec(ctx, &variant->vvalue.vt_i4_array.vdata, vals, elems);
|
|
}
|