2 * Unix SMB/CIFS implementation.
4 * Window Search Service
6 * Copyright (c) Noel Power
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "librpc/wsp/wsp_util.h"
23 #include "librpc/gen_ndr/wsp.h"
24 #include "librpc/gen_ndr/ndr_wsp.h"
25 #include "lib/util/strv_util.h"
26 #include "lib/util/strv.h"
27 #include "lib/util/util_str_hex.h"
28 #include "source3/param/param_proto.h"
29 #include "lib/util/dlinklist.h"
31 #define BUFFER_SIZE 1024000
32 struct guidtopropmap_holder
34 struct guidtopropmap
*guidtopropmaploc
;
37 struct full_propset_info_list
{
38 struct full_propset_info_list
*prev
, *next
;
39 struct full_propset_info info
;
42 struct guidtopropmap
{
43 struct guidtopropmap
*prev
, *next
;
45 struct full_propset_info_list
*propset
;
48 static struct guidtopropmap
*find_guid_props(
49 struct guidtopropmap_holder
*holder
,
50 const struct GUID
*guid
)
52 struct guidtopropmap
*mapitem
;
53 for (mapitem
= holder
->guidtopropmaploc
; mapitem
; mapitem
= mapitem
->next
) {
54 if (GUID_equal(guid
, &mapitem
->guid
)) {
61 static bool getbool(char *str
)
63 char *cpy
= talloc_strdup(NULL
, str
);
66 trim_string(cpy
, " ", " ");
67 if (strequal("TRUE", cpy
)) {
81 {"String", VT_LPWSTR
},
84 {"Buffer", VT_BLOB_OBJECT
},
92 {"DateTime", VT_FILETIME
},
96 static uint16_t getvtype(char *str
, bool isvec
)
98 uint16_t result
= UINT16_MAX
;
100 for (i
= 0; i
< ARRAY_SIZE(vtype_map
); i
++) {
101 if (strequal(vtype_map
[i
].typename
, str
)) {
102 result
= vtype_map
[i
].type
;
112 static bool parse_csv_line(TALLOC_CTX
*ctx
,
113 char **csvs
, size_t num_values
,
114 struct guidtopropmap_holder
*propmap_holder
)
116 struct guidtopropmap
*mapitem
= NULL
;
117 struct full_propset_info_list
*item
= NULL
;
119 char *guid_str
= NULL
;
123 item
= talloc_zero(ctx
,
124 struct full_propset_info_list
);
129 item
->info
.in_inverted_index
= false;
130 item
->info
.is_column
= true;
131 item
->info
.can_col_be_indexed
= true;
133 if (strlen(csvs
[1])) {
134 guid_str
= talloc_strdup(ctx
, csvs
[1]);
138 DBG_ERR("out of memory\n");
142 if (!trim_string(guid_str
, "{", "}")) {
146 if (strlen(csvs
[0])) {
147 char *tmp
= talloc_strdup(item
, csvs
[0]);
148 trim_string(tmp
, " ", " ");
149 item
->info
.name
= tmp
;
152 if (strlen(csvs
[2])) {
153 item
->info
.id
= atoi(csvs
[2]);
156 if (strlen(csvs
[3])) {
157 item
->info
.in_inverted_index
= getbool(csvs
[3]);
160 if (strlen(csvs
[4])) {
161 item
->info
.is_column
= getbool(csvs
[4]);
164 if (strlen(csvs
[5])) {
165 item
->info
.can_col_be_indexed
= getbool(csvs
[5]);
168 if (strlen(csvs
[6])) {
171 if (strlen(csvs
[0])) {
172 isvec
= getbool(csvs
[8]);
174 type
= getvtype(csvs
[6], isvec
);
175 if (type
== UINT16_MAX
) {
176 DBG_ERR("failed to parse type\n");
179 item
->info
.vtype
= type
;
182 ok
= parse_guid_string(guid_str
, &guid
);
187 mapitem
= find_guid_props(propmap_holder
, &guid
);
189 mapitem
= talloc_zero(propmap_holder
,
190 struct guidtopropmap
);
194 mapitem
->guid
= guid
;
195 DLIST_ADD_END(propmap_holder
->guidtopropmaploc
, mapitem
);
198 talloc_steal(mapitem
, item
);
199 DLIST_ADD_END(mapitem
->propset
, item
);
203 static bool parse_properties_line(TALLOC_CTX
*ctx
,
205 struct guidtopropmap_holder
*propmap_holder
)
210 char** csv_line
= NULL
;
214 ret
= strv_split(ctx
,
220 DBG_ERR("failed to split line\n");
224 len
= strv_count(strv
);
227 DBG_WARNING("skipping line as it doesn't have "
232 csv_line
= talloc_zero_array(ctx
,
237 DBG_ERR("out of memory\n");
240 for (pos
= 0; pos
< talloc_array_length(csv_line
); pos
++) {
241 t
= strv_next(strv
, t
);
242 /* the scraped property file can have a non ascii char */
243 if (strlen(t
) == 1 && *t
== 0xa0) {
244 csv_line
[pos
] = talloc_strdup(csv_line
,
247 csv_line
[pos
] = talloc_strdup(csv_line
,
250 trim_string(csv_line
[pos
], " ", " ");
253 if (!parse_csv_line(csv_line
, csv_line
, len
, propmap_holder
)) {
254 DBG_ERR("failed to parse line\n");
255 TALLOC_FREE(csv_line
);
258 TALLOC_FREE(csv_line
);
262 static bool parse_properties_csvfile(TALLOC_CTX
*ctx
,
263 struct guidtopropmap_holder
*propmap_holder
,
264 const char* filename
)
270 if (filename
== NULL
|| strlen(filename
) == 0) {
274 lines
= file_lines_load(filename
,
279 DBG_ERR("Failed to load %s\n", filename
);
282 DBG_ERR("parsed %d lines\n", numlines
);
284 for (i
= 0; i
< numlines
; i
++) {
285 TALLOC_CTX
*line_ctx
= talloc_init("line context");
287 DBG_ERR("out of memory\n");
291 trim_string(lines
[i
], " ", " ");
292 if (lines
[i
][0] == '#') {
293 DBG_WARNING("skipping comment at line %d.\n)", i
);
294 TALLOC_FREE(line_ctx
);
298 if (!parse_properties_line(line_ctx
,
301 DBG_ERR("Failed to parse line %d\n", i
);
303 TALLOC_FREE(line_ctx
);
308 static bool populate_map(struct guidtopropmap_holder
*propmap_holder
)
310 const char * path
= NULL
;
311 path
= lp_wsp_property_file();
313 /* first populate the map from property file */
315 parse_properties_csvfile(propmap_holder
, propmap_holder
, path
);
321 static struct guidtopropmap_holder
*propmap(void)
323 static struct guidtopropmap_holder
*holder
= NULL
;
326 holder
= talloc_zero(NULL
, struct guidtopropmap_holder
);
328 populate_map(holder
);
335 const struct full_propset_info
*get_propset_info_with_guid(
336 const char *prop_name
,
337 struct GUID
*propset_guid
)
339 const struct full_propset_info
*result
= NULL
;
340 struct guidtopropmap_holder
*holder
= NULL
;
341 struct guidtopropmap
*mapitem
= NULL
;
344 const struct full_guid_propset
*guid_propset
= NULL
;
346 /* search builtin props first */
347 for (i
= 0; full_propertyset
[i
].prop_info
!= NULL
; i
++) {
348 const struct full_propset_info
*item
= NULL
;
349 guid_propset
= &full_propertyset
[i
];
350 item
= guid_propset
->prop_info
;
352 if (strequal(prop_name
, item
->name
)) {
353 *propset_guid
= guid_propset
->guid
;
368 /* if we didn't find a match in builtin props try the extra props */
370 for (mapitem
= holder
->guidtopropmaploc
; mapitem
;
371 mapitem
= mapitem
->next
) {
372 struct full_propset_info_list
*propitem
;
373 for (propitem
= mapitem
->propset
; propitem
;
374 propitem
= propitem
->next
) {
375 if (strequal(prop_name
, propitem
->info
.name
)) {
376 *propset_guid
= mapitem
->guid
;
377 result
= &propitem
->info
;
385 const struct full_propset_info
*get_prop_info(const char *prop_name
)
387 const struct full_propset_info
*result
= NULL
;
389 result
= get_propset_info_with_guid(prop_name
, &guid
);
393 char *prop_from_fullprop(TALLOC_CTX
*ctx
, struct wsp_cfullpropspec
*fullprop
)
397 const struct full_propset_info
*item
= NULL
;
398 const struct full_propset_info_list
*prop_item
= NULL
;
399 bool search_by_id
= (fullprop
->ulkind
== PRSPEC_PROPID
);
400 struct guidtopropmap_holder
*holder
= NULL
;
401 struct guidtopropmap
*mapitem
= NULL
;
403 /* check builtin properties */
404 for (i
= 0; full_propertyset
[i
].prop_info
!= NULL
; i
++) {
406 if (GUID_equal(&fullprop
->guidpropset
,
407 &full_propertyset
[i
].guid
)) {
408 item
= full_propertyset
[i
].prop_info
;
415 if( fullprop
->name_or_id
.prspec
== item
->id
) {
416 result
= talloc_strdup(ctx
, item
->name
);
419 } else if (strcmp(item
->name
,
420 fullprop
->name_or_id
.propname
.vstring
)
422 result
= talloc_strdup(ctx
, item
->name
);
429 /* not found, search the extra props */
433 for (mapitem
= holder
->guidtopropmaploc
; mapitem
;
434 mapitem
= mapitem
->next
) {
435 if (GUID_equal(&fullprop
->guidpropset
,
437 prop_item
= mapitem
->propset
;
442 for (;prop_item
; prop_item
= prop_item
->next
) {
444 if(fullprop
->name_or_id
.prspec
==
445 prop_item
->info
.id
) {
446 result
= talloc_strdup(ctx
,
447 prop_item
->info
.name
);
450 } else if (strcmp(prop_item
->info
.name
,
451 fullprop
->name_or_id
.propname
.vstring
) == 0) {
452 result
= talloc_strdup(ctx
,
453 prop_item
->info
.name
);
460 result
= GUID_string(ctx
, &fullprop
->guidpropset
);
463 result
= talloc_asprintf(result
, "%s/%d", result
,
464 fullprop
->name_or_id
.prspec
);
466 result
= talloc_asprintf(result
, "%s/%s", result
,
467 fullprop
->name_or_id
.propname
.vstring
);
473 const char *genmeth_to_string(uint32_t genmethod
)
475 const char *result
= NULL
;
481 result
= "starts with";
484 result
= "matches inflection";
493 bool is_operator(struct wsp_crestriction
*restriction
) {
495 switch(restriction
->ultype
) {
508 const char *op_as_string(struct wsp_crestriction
*restriction
)
510 const char *op
= NULL
;
511 if (is_operator(restriction
)) {
512 switch(restriction
->ultype
) {
523 } else if (restriction
->ultype
== RTPROPERTY
) {
524 struct wsp_cpropertyrestriction
*prop_restr
=
525 &restriction
->restriction
.cpropertyrestriction
;
526 switch (prop_restr
->relop
& 0XF) {
548 } else if (restriction
->ultype
== RTCONTENT
) {
549 struct wsp_ccontentrestriction
*content
= NULL
;
550 content
= &restriction
->restriction
.ccontentrestriction
;
551 op
= genmeth_to_string(content
->ulgeneratemethod
);
552 } else if (restriction
->ultype
== RTNATLANGUAGE
) {
558 struct wsp_cfullpropspec
*get_full_prop(struct wsp_crestriction
*restriction
)
560 struct wsp_cfullpropspec
*result
;
561 switch (restriction
->ultype
) {
563 result
= &restriction
->restriction
.cpropertyrestriction
.property
;
566 result
= &restriction
->restriction
.ccontentrestriction
.property
;
569 result
= &restriction
->restriction
.cnatlanguagerestriction
.property
;
578 const char *variant_as_string(TALLOC_CTX
*ctx
,
579 struct wsp_cbasestoragevariant
*value
, bool quote
)
581 const char* result
= NULL
;
582 switch(value
->vtype
) {
584 result
= talloc_asprintf(ctx
, "%u",
585 value
->vvalue
.vt_ui1
);
589 result
= talloc_asprintf(ctx
, "%d",
590 value
->vvalue
.vt_i4
);
595 result
= talloc_asprintf(ctx
, "%u",
596 value
->vvalue
.vt_ui4
);
600 result
= talloc_asprintf(ctx
, "%u",
601 value
->vvalue
.vt_ui2
);
604 result
= talloc_asprintf(ctx
, "%s",
605 value
->vvalue
.vt_ui2
== 0xFFFF ?
610 NTTIME filetime
= value
->vvalue
.vt_ui8
;
612 struct tm
*tm
= NULL
;
613 char datestring
[256];
614 unixtime
= nt_time_to_unix(filetime
);
615 tm
= gmtime(&unixtime
);
616 strftime(datestring
, sizeof(datestring
), "%FT%TZ", tm
);
617 result
= talloc_strdup(ctx
, datestring
);
622 if (sizeof(f
) != sizeof(value
->vvalue
.vt_ui4
)) {
623 DBG_ERR("can't convert float\n");
627 (void*)&value
->vvalue
.vt_ui4
,
628 sizeof(value
->vvalue
.vt_ui4
));
629 result
= talloc_asprintf(ctx
, "%f",
634 /* should this really be unsigned ? */
636 if (sizeof(dval
) != sizeof(value
->vvalue
.vt_i8
)) {
637 DBG_ERR("can't convert double\n");
641 (void*)&value
->vvalue
.vt_i8
,
643 result
= talloc_asprintf(ctx
, "%f",
648 result
= talloc_asprintf(ctx
, "%" PRIi64
,
649 value
->vvalue
.vt_i8
);
653 result
= talloc_asprintf(ctx
, "%" PRIu64
,
654 value
->vvalue
.vt_ui8
);
658 result
= talloc_asprintf(ctx
, "%s%s%s",
660 value
->vvalue
.vt_lpwstr
.value
,
663 case VT_LPWSTR
| VT_VECTOR
: {
665 value
->vvalue
.vt_lpwstr_v
.vvector_elements
;
667 for(i
= 0; i
< num_elems
; i
++) {
668 struct vt_lpwstr_vec
*vec
;
670 vec
= &value
->vvalue
.vt_lpwstr_v
;
671 val
= vec
->vvector_data
[i
].value
;
675 result
? result
: "",
684 DBG_INFO("can't represent unsupported vtype 0x%x as string\n",
691 static const struct {
703 {VT_DATE
, "VT_DATE"},
704 {VT_BSTR
, "VT_BSTR"},
712 {VT_UINT
, "VT_UINT"},
713 {VT_ERROR
, "VT_ERROR"},
714 {VT_BOOL
, "VT_BOOL"},
715 {VT_VARIANT
, "VT_VARIANT"},
716 {VT_DECIMAL
, "VT_DECIMAL"},
717 {VT_FILETIME
, "VT_FILETIME"},
718 {VT_BLOB
, "VT_BLOB"},
719 {VT_BLOB_OBJECT
, "VT_BLOB_OBJECT"},
720 {VT_CLSID
, "VT_CLSID"},
721 {VT_LPSTR
, "VT_LPSTR"},
722 {VT_LPWSTR
, "VT_LPWSTR"},
723 {VT_COMPRESSED_LPWSTR
, "VT_COMPRESSED_LPWSTR"},
726 const char *get_vtype_name(uint32_t type
)
728 const char *type_name
= NULL
;
729 static char result_buf
[255];
731 uint32_t temp
= type
& ~(VT_VECTOR
| VT_ARRAY
);
732 for (i
= 0; i
< ARRAY_SIZE(typename_map
); i
++) {
733 if (temp
== typename_map
[i
].id
) {
734 type_name
= typename_map
[i
].name
;
738 if (type
& VT_VECTOR
) {
739 snprintf(result_buf
, sizeof(result_buf
), "Vector | %s", type_name
);
740 } else if (type
& VT_ARRAY
) {
741 snprintf(result_buf
, sizeof(result_buf
), "Array | %s", type_name
);
743 snprintf(result_buf
, sizeof(result_buf
), "%s", type_name
);
748 bool is_variable_size(uint16_t vtype
)
753 case VT_COMPRESSED_LPWSTR
:
767 const char *get_store_status(uint8_t status_byte
)
770 switch(status_byte
) {
772 result
= "StoreStatusOk";
775 result
= "StoreStatusDeferred";
778 result
= "StoreStatusNull";
781 result
= "Unknown Status";
787 void set_variant_lpwstr(TALLOC_CTX
*ctx
,
788 struct wsp_cbasestoragevariant
*vvalue
,
789 const char *string_val
)
791 vvalue
->vtype
= VT_LPWSTR
;
792 vvalue
->vvalue
.vt_lpwstr
.value
= talloc_strdup(ctx
, string_val
);
795 void set_variant_i4(TALLOC_CTX
*ctx
,
796 struct wsp_cbasestoragevariant
*vvalue
,
799 vvalue
->vtype
= VT_I4
;
800 vvalue
->vvalue
.vt_i4
= val
;
803 void set_variant_vt_bool(TALLOC_CTX
*ctx
,
804 struct wsp_cbasestoragevariant
*variant
,
807 variant
->vtype
= VT_BOOL
;
808 variant
->vvalue
.vt_bool
= bval
;
811 static void fill_int32_vec(TALLOC_CTX
* ctx
,
813 int32_t* ivector
, uint32_t elems
)
816 int32_t *dest
= talloc_zero_array(ctx
, int32_t, elems
);
817 for ( i
= 0; i
< elems
; i
++ ) {
818 dest
[ i
] = ivector
[ i
];
823 void set_variant_i4_vector(TALLOC_CTX
*ctx
,
824 struct wsp_cbasestoragevariant
*variant
,
825 int32_t* ivector
, uint32_t elems
)
827 variant
->vtype
= VT_VECTOR
| VT_I4
;
828 variant
->vvalue
.vt_i4_vec
.vvector_elements
= elems
;
829 fill_int32_vec(ctx
, &variant
->vvalue
.vt_i4_vec
.vvector_data
, ivector
, elems
);
832 static void fill_string_vec(TALLOC_CTX
* ctx
,
833 struct wsp_cbasestoragevariant
*variant
,
834 const char **strings
, uint16_t elems
)
837 variant
->vvalue
.vt_lpwstr_v
.vvector_elements
= elems
;
838 variant
->vvalue
.vt_lpwstr_v
.vvector_data
= talloc_zero_array(ctx
,
842 for( i
= 0; i
< elems
; i
++ ) {
843 variant
->vvalue
.vt_lpwstr_v
.vvector_data
[ i
].value
= talloc_strdup(ctx
, strings
[ i
]);
847 static void fill_bstr_vec(TALLOC_CTX
*ctx
,
848 struct vt_bstr
**pvector
,
849 const char **strings
, uint16_t elems
)
852 struct vt_bstr
*vdata
= talloc_zero_array(ctx
, struct vt_bstr
, elems
);
854 for( i
= 0; i
< elems
; i
++ ) {
855 vdata
[ i
].value
= talloc_strdup(ctx
, strings
[ i
]);
860 void set_variant_bstr(TALLOC_CTX
*ctx
, struct wsp_cbasestoragevariant
*variant
,
861 const char *string_val
)
863 variant
->vtype
= VT_BSTR
;
864 variant
->vvalue
.vt_bstr
.value
= talloc_strdup(ctx
, string_val
);
867 void set_variant_lpwstr_vector(TALLOC_CTX
*ctx
,
868 struct wsp_cbasestoragevariant
*variant
,
869 const char **string_vals
, uint32_t elems
)
871 variant
->vtype
= VT_LPWSTR
| VT_VECTOR
;
872 fill_string_vec(ctx
, variant
, string_vals
, elems
);
875 void set_variant_array_bstr(TALLOC_CTX
*ctx
,
876 struct wsp_cbasestoragevariant
*variant
,
877 const char **string_vals
, uint16_t elems
)
879 variant
->vtype
= VT_BSTR
| VT_ARRAY
;
880 variant
->vvalue
.vt_bstr_array
.cdims
= 1;
881 variant
->vvalue
.vt_bstr_array
.ffeatures
= 0;
883 variant
->vvalue
.vt_bstr_array
.rgsabound
=
884 talloc_zero_array(ctx
, struct safearraybound
, 1);
886 variant
->vvalue
.vt_bstr_array
.rgsabound
[0].celements
= elems
;
887 variant
->vvalue
.vt_bstr_array
.rgsabound
[0].ilbound
= 0;
888 variant
->vvalue
.vt_bstr_array
.cbelements
= 0;
889 fill_bstr_vec(ctx
, &variant
->vvalue
.vt_bstr_array
.vdata
,
892 * if cbelements is the num bytes per elem it kindof means each
893 * string in the array must be the same size ?
897 variant
->vvalue
.vt_bstr_array
.cbelements
=
898 strlen_m_term(variant
->vvalue
.vt_bstr_array
.vdata
[0].value
)*2;
902 /* create single dim array of vt_i4 */
903 void set_variant_array_i4(TALLOC_CTX
*ctx
,
904 struct wsp_cbasestoragevariant
*variant
,
905 int32_t *vals
, uint16_t elems
)
907 /* #TODO see if we can combine with other set_variant_array methods */
908 variant
->vtype
= VT_I4
| VT_ARRAY
;
909 variant
->vvalue
.vt_i4_array
.cdims
= 1;
910 variant
->vvalue
.vt_i4_array
.ffeatures
= 0;
912 variant
->vvalue
.vt_i4_array
.rgsabound
=
913 talloc_zero_array(ctx
, struct safearraybound
, 1);
915 variant
->vvalue
.vt_i4_array
.rgsabound
[0].celements
= elems
;
916 variant
->vvalue
.vt_i4_array
.rgsabound
[0].ilbound
= 0;
917 variant
->vvalue
.vt_i4_array
.cbelements
= sizeof(uint32_t);
918 fill_int32_vec(ctx
, &variant
->vvalue
.vt_i4_array
.vdata
, vals
, elems
);