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 "lib/util/util_file.h"
23 #include "librpc/wsp/wsp_util.h"
24 #include "librpc/gen_ndr/wsp.h"
25 #include "librpc/gen_ndr/ndr_wsp.h"
26 #include "lib/util/strv_util.h"
27 #include "lib/util/strv.h"
28 #include "lib/util/util_str_hex.h"
29 #include "source3/param/param_proto.h"
30 #include "lib/util/dlinklist.h"
32 #define BUFFER_SIZE 1024000
33 struct guidtopropmap_holder
35 struct guidtopropmap
*guidtopropmaploc
;
38 struct full_propset_info_list
{
39 struct full_propset_info_list
*prev
, *next
;
40 struct full_propset_info info
;
43 struct guidtopropmap
{
44 struct guidtopropmap
*prev
, *next
;
46 struct full_propset_info_list
*propset
;
49 static struct guidtopropmap
*find_guid_props(
50 struct guidtopropmap_holder
*holder
,
51 const struct GUID
*guid
)
53 struct guidtopropmap
*mapitem
;
54 for (mapitem
= holder
->guidtopropmaploc
; mapitem
; mapitem
= mapitem
->next
) {
55 if (GUID_equal(guid
, &mapitem
->guid
)) {
62 static bool getbool(char *str
)
64 char *cpy
= talloc_strdup(NULL
, str
);
67 trim_string(cpy
, " ", " ");
68 if (strequal("TRUE", cpy
)) {
82 {"String", VT_LPWSTR
},
85 {"Buffer", VT_BLOB_OBJECT
},
93 {"DateTime", VT_FILETIME
},
97 static uint16_t getvtype(char *str
, bool isvec
)
99 uint16_t result
= UINT16_MAX
;
101 for (i
= 0; i
< ARRAY_SIZE(vtype_map
); i
++) {
102 if (strequal(vtype_map
[i
].typename
, str
)) {
103 result
= vtype_map
[i
].type
;
113 static bool parse_csv_line(TALLOC_CTX
*ctx
,
114 char **csvs
, size_t num_values
,
115 struct guidtopropmap_holder
*propmap_holder
)
117 struct guidtopropmap
*mapitem
= NULL
;
118 struct full_propset_info_list
*item
= NULL
;
120 char *guid_str
= NULL
;
124 item
= talloc_zero(ctx
,
125 struct full_propset_info_list
);
130 item
->info
.in_inverted_index
= false;
131 item
->info
.is_column
= true;
132 item
->info
.can_col_be_indexed
= true;
134 if (strlen(csvs
[1])) {
135 guid_str
= talloc_strdup(ctx
, csvs
[1]);
139 DBG_ERR("out of memory\n");
143 if (!trim_string(guid_str
, "{", "}")) {
147 if (strlen(csvs
[0])) {
148 char *tmp
= talloc_strdup(item
, csvs
[0]);
149 trim_string(tmp
, " ", " ");
150 item
->info
.name
= tmp
;
153 if (strlen(csvs
[2])) {
154 item
->info
.id
= atoi(csvs
[2]);
157 if (strlen(csvs
[3])) {
158 item
->info
.in_inverted_index
= getbool(csvs
[3]);
161 if (strlen(csvs
[4])) {
162 item
->info
.is_column
= getbool(csvs
[4]);
165 if (strlen(csvs
[5])) {
166 item
->info
.can_col_be_indexed
= getbool(csvs
[5]);
169 if (strlen(csvs
[6])) {
172 if (strlen(csvs
[0])) {
173 isvec
= getbool(csvs
[8]);
175 type
= getvtype(csvs
[6], isvec
);
176 if (type
== UINT16_MAX
) {
177 DBG_ERR("failed to parse type\n");
180 item
->info
.vtype
= type
;
183 ok
= parse_guid_string(guid_str
, &guid
);
188 mapitem
= find_guid_props(propmap_holder
, &guid
);
190 mapitem
= talloc_zero(propmap_holder
,
191 struct guidtopropmap
);
195 mapitem
->guid
= guid
;
196 DLIST_ADD_END(propmap_holder
->guidtopropmaploc
, mapitem
);
199 talloc_steal(mapitem
, item
);
200 DLIST_ADD_END(mapitem
->propset
, item
);
204 static bool parse_properties_line(TALLOC_CTX
*ctx
,
206 struct guidtopropmap_holder
*propmap_holder
)
211 char** csv_line
= NULL
;
215 ret
= strv_split(ctx
,
221 DBG_ERR("failed to split line\n");
225 len
= strv_count(strv
);
228 DBG_WARNING("skipping line as it doesn't have "
233 csv_line
= talloc_zero_array(ctx
,
238 DBG_ERR("out of memory\n");
241 for (pos
= 0; pos
< talloc_array_length(csv_line
); pos
++) {
242 t
= strv_next(strv
, t
);
243 /* the scraped property file can have a non ascii char */
244 if (strlen(t
) == 1 && *t
== 0xa0) {
245 csv_line
[pos
] = talloc_strdup(csv_line
,
248 csv_line
[pos
] = talloc_strdup(csv_line
,
251 trim_string(csv_line
[pos
], " ", " ");
254 if (!parse_csv_line(csv_line
, csv_line
, len
, propmap_holder
)) {
255 DBG_ERR("failed to parse line\n");
256 TALLOC_FREE(csv_line
);
259 TALLOC_FREE(csv_line
);
263 static bool parse_properties_csvfile(TALLOC_CTX
*ctx
,
264 struct guidtopropmap_holder
*propmap_holder
,
265 const char* filename
)
271 if (filename
== NULL
|| strlen(filename
) == 0) {
275 lines
= file_lines_load(filename
,
280 DBG_ERR("Failed to load %s\n", filename
);
283 DBG_ERR("parsed %d lines\n", numlines
);
285 for (i
= 0; i
< numlines
; i
++) {
286 TALLOC_CTX
*line_ctx
= talloc_init("line context");
288 DBG_ERR("out of memory\n");
292 trim_string(lines
[i
], " ", " ");
293 if (lines
[i
][0] == '#') {
294 DBG_WARNING("skipping comment at line %d.\n)", i
);
295 TALLOC_FREE(line_ctx
);
299 if (!parse_properties_line(line_ctx
,
302 DBG_ERR("Failed to parse line %d\n", i
);
304 TALLOC_FREE(line_ctx
);
309 static bool populate_map(struct guidtopropmap_holder
*propmap_holder
)
311 const char * path
= NULL
;
312 path
= lp_wsp_property_file();
314 /* first populate the map from property file */
316 parse_properties_csvfile(propmap_holder
, propmap_holder
, path
);
322 static struct guidtopropmap_holder
*propmap(void)
324 static struct guidtopropmap_holder
*holder
= NULL
;
327 holder
= talloc_zero(NULL
, struct guidtopropmap_holder
);
329 populate_map(holder
);
336 const struct full_propset_info
*get_propset_info_with_guid(
337 const char *prop_name
,
338 struct GUID
*propset_guid
)
340 const struct full_propset_info
*result
= NULL
;
341 struct guidtopropmap_holder
*holder
= NULL
;
342 struct guidtopropmap
*mapitem
= NULL
;
345 const struct full_guid_propset
*guid_propset
= NULL
;
347 /* search builtin props first */
348 for (i
= 0; full_propertyset
[i
].prop_info
!= NULL
; i
++) {
349 const struct full_propset_info
*item
= NULL
;
350 guid_propset
= &full_propertyset
[i
];
351 item
= guid_propset
->prop_info
;
353 if (strequal(prop_name
, item
->name
)) {
354 *propset_guid
= guid_propset
->guid
;
369 /* if we didn't find a match in builtin props try the extra props */
371 for (mapitem
= holder
->guidtopropmaploc
; mapitem
;
372 mapitem
= mapitem
->next
) {
373 struct full_propset_info_list
*propitem
;
374 for (propitem
= mapitem
->propset
; propitem
;
375 propitem
= propitem
->next
) {
376 if (strequal(prop_name
, propitem
->info
.name
)) {
377 *propset_guid
= mapitem
->guid
;
378 result
= &propitem
->info
;
386 const struct full_propset_info
*get_prop_info(const char *prop_name
)
388 const struct full_propset_info
*result
= NULL
;
390 result
= get_propset_info_with_guid(prop_name
, &guid
);
394 char *prop_from_fullprop(TALLOC_CTX
*ctx
, struct wsp_cfullpropspec
*fullprop
)
398 const struct full_propset_info
*item
= NULL
;
399 const struct full_propset_info_list
*prop_item
= NULL
;
400 bool search_by_id
= (fullprop
->ulkind
== PRSPEC_PROPID
);
401 struct guidtopropmap_holder
*holder
= NULL
;
402 struct guidtopropmap
*mapitem
= NULL
;
404 /* check builtin properties */
405 for (i
= 0; full_propertyset
[i
].prop_info
!= NULL
; i
++) {
407 if (GUID_equal(&fullprop
->guidpropset
,
408 &full_propertyset
[i
].guid
)) {
409 item
= full_propertyset
[i
].prop_info
;
416 if( fullprop
->name_or_id
.prspec
== item
->id
) {
417 result
= talloc_strdup(ctx
, item
->name
);
420 } else if (strcmp(item
->name
,
421 fullprop
->name_or_id
.propname
.vstring
)
423 result
= talloc_strdup(ctx
, item
->name
);
430 /* not found, search the extra props */
434 for (mapitem
= holder
->guidtopropmaploc
; mapitem
;
435 mapitem
= mapitem
->next
) {
436 if (GUID_equal(&fullprop
->guidpropset
,
438 prop_item
= mapitem
->propset
;
443 for (;prop_item
; prop_item
= prop_item
->next
) {
445 if(fullprop
->name_or_id
.prspec
==
446 prop_item
->info
.id
) {
447 result
= talloc_strdup(ctx
,
448 prop_item
->info
.name
);
451 } else if (strcmp(prop_item
->info
.name
,
452 fullprop
->name_or_id
.propname
.vstring
) == 0) {
453 result
= talloc_strdup(ctx
,
454 prop_item
->info
.name
);
461 result
= GUID_string(ctx
, &fullprop
->guidpropset
);
464 result
= talloc_asprintf(result
, "%s/%d", result
,
465 fullprop
->name_or_id
.prspec
);
467 result
= talloc_asprintf(result
, "%s/%s", result
,
468 fullprop
->name_or_id
.propname
.vstring
);
474 const char *genmeth_to_string(uint32_t genmethod
)
476 const char *result
= NULL
;
482 result
= "starts with";
485 result
= "matches inflection";
494 bool is_operator(struct wsp_crestriction
*restriction
) {
496 switch(restriction
->ultype
) {
509 const char *op_as_string(struct wsp_crestriction
*restriction
)
511 const char *op
= NULL
;
512 if (is_operator(restriction
)) {
513 switch(restriction
->ultype
) {
524 } else if (restriction
->ultype
== RTPROPERTY
) {
525 struct wsp_cpropertyrestriction
*prop_restr
=
526 &restriction
->restriction
.cpropertyrestriction
;
527 switch (prop_restr
->relop
& 0XF) {
549 } else if (restriction
->ultype
== RTCONTENT
) {
550 struct wsp_ccontentrestriction
*content
= NULL
;
551 content
= &restriction
->restriction
.ccontentrestriction
;
552 op
= genmeth_to_string(content
->ulgeneratemethod
);
553 } else if (restriction
->ultype
== RTNATLANGUAGE
) {
559 struct wsp_cfullpropspec
*get_full_prop(struct wsp_crestriction
*restriction
)
561 struct wsp_cfullpropspec
*result
;
562 switch (restriction
->ultype
) {
564 result
= &restriction
->restriction
.cpropertyrestriction
.property
;
567 result
= &restriction
->restriction
.ccontentrestriction
.property
;
570 result
= &restriction
->restriction
.cnatlanguagerestriction
.property
;
579 const char *variant_as_string(TALLOC_CTX
*ctx
,
580 struct wsp_cbasestoragevariant
*value
, bool quote
)
582 const char* result
= NULL
;
583 switch(value
->vtype
) {
585 result
= talloc_asprintf(ctx
, "%u",
586 value
->vvalue
.vt_ui1
);
590 result
= talloc_asprintf(ctx
, "%d",
591 value
->vvalue
.vt_i4
);
596 result
= talloc_asprintf(ctx
, "%u",
597 value
->vvalue
.vt_ui4
);
601 result
= talloc_asprintf(ctx
, "%u",
602 value
->vvalue
.vt_ui2
);
605 result
= talloc_asprintf(ctx
, "%s",
606 value
->vvalue
.vt_ui2
== 0xFFFF ?
611 NTTIME filetime
= value
->vvalue
.vt_ui8
;
613 struct tm
*tm
= NULL
;
614 char datestring
[256];
615 unixtime
= nt_time_to_unix(filetime
);
616 tm
= gmtime(&unixtime
);
617 strftime(datestring
, sizeof(datestring
), "%FT%TZ", tm
);
618 result
= talloc_strdup(ctx
, datestring
);
623 if (sizeof(f
) != sizeof(value
->vvalue
.vt_ui4
)) {
624 DBG_ERR("can't convert float\n");
628 (void*)&value
->vvalue
.vt_ui4
,
629 sizeof(value
->vvalue
.vt_ui4
));
630 result
= talloc_asprintf(ctx
, "%f",
635 /* should this really be unsigned ? */
637 if (sizeof(dval
) != sizeof(value
->vvalue
.vt_i8
)) {
638 DBG_ERR("can't convert double\n");
642 (void*)&value
->vvalue
.vt_i8
,
644 result
= talloc_asprintf(ctx
, "%f",
649 result
= talloc_asprintf(ctx
, "%" PRIi64
,
650 value
->vvalue
.vt_i8
);
654 result
= talloc_asprintf(ctx
, "%" PRIu64
,
655 value
->vvalue
.vt_ui8
);
659 result
= talloc_asprintf(ctx
, "%s%s%s",
661 value
->vvalue
.vt_lpwstr
.value
,
664 case VT_LPWSTR
| VT_VECTOR
: {
666 value
->vvalue
.vt_lpwstr_v
.vvector_elements
;
668 for(i
= 0; i
< num_elems
; i
++) {
669 struct vt_lpwstr_vec
*vec
;
671 vec
= &value
->vvalue
.vt_lpwstr_v
;
672 val
= vec
->vvector_data
[i
].value
;
676 result
? result
: "",
685 DBG_INFO("can't represent unsupported vtype 0x%x as string\n",
692 static const struct {
704 {VT_DATE
, "VT_DATE"},
705 {VT_BSTR
, "VT_BSTR"},
713 {VT_UINT
, "VT_UINT"},
714 {VT_ERROR
, "VT_ERROR"},
715 {VT_BOOL
, "VT_BOOL"},
716 {VT_VARIANT
, "VT_VARIANT"},
717 {VT_DECIMAL
, "VT_DECIMAL"},
718 {VT_FILETIME
, "VT_FILETIME"},
719 {VT_BLOB
, "VT_BLOB"},
720 {VT_BLOB_OBJECT
, "VT_BLOB_OBJECT"},
721 {VT_CLSID
, "VT_CLSID"},
722 {VT_LPSTR
, "VT_LPSTR"},
723 {VT_LPWSTR
, "VT_LPWSTR"},
724 {VT_COMPRESSED_LPWSTR
, "VT_COMPRESSED_LPWSTR"},
727 const char *get_vtype_name(uint32_t type
)
729 const char *type_name
= NULL
;
730 static char result_buf
[255];
732 uint32_t temp
= type
& ~(VT_VECTOR
| VT_ARRAY
);
733 for (i
= 0; i
< ARRAY_SIZE(typename_map
); i
++) {
734 if (temp
== typename_map
[i
].id
) {
735 type_name
= typename_map
[i
].name
;
739 if (type
& VT_VECTOR
) {
740 snprintf(result_buf
, sizeof(result_buf
), "Vector | %s", type_name
);
741 } else if (type
& VT_ARRAY
) {
742 snprintf(result_buf
, sizeof(result_buf
), "Array | %s", type_name
);
744 snprintf(result_buf
, sizeof(result_buf
), "%s", type_name
);
749 bool is_variable_size(uint16_t vtype
)
754 case VT_COMPRESSED_LPWSTR
:
768 const char *get_store_status(uint8_t status_byte
)
771 switch(status_byte
) {
773 result
= "StoreStatusOk";
776 result
= "StoreStatusDeferred";
779 result
= "StoreStatusNull";
782 result
= "Unknown Status";
788 void set_variant_lpwstr(TALLOC_CTX
*ctx
,
789 struct wsp_cbasestoragevariant
*vvalue
,
790 const char *string_val
)
792 vvalue
->vtype
= VT_LPWSTR
;
793 vvalue
->vvalue
.vt_lpwstr
.value
= talloc_strdup(ctx
, string_val
);
796 void set_variant_i4(TALLOC_CTX
*ctx
,
797 struct wsp_cbasestoragevariant
*vvalue
,
800 vvalue
->vtype
= VT_I4
;
801 vvalue
->vvalue
.vt_i4
= val
;
804 void set_variant_vt_bool(TALLOC_CTX
*ctx
,
805 struct wsp_cbasestoragevariant
*variant
,
808 variant
->vtype
= VT_BOOL
;
809 variant
->vvalue
.vt_bool
= bval
;
812 static void fill_int32_vec(TALLOC_CTX
* ctx
,
814 int32_t* ivector
, uint32_t elems
)
817 int32_t *dest
= talloc_zero_array(ctx
, int32_t, elems
);
818 for ( i
= 0; i
< elems
; i
++ ) {
819 dest
[ i
] = ivector
[ i
];
824 void set_variant_i4_vector(TALLOC_CTX
*ctx
,
825 struct wsp_cbasestoragevariant
*variant
,
826 int32_t* ivector
, uint32_t elems
)
828 variant
->vtype
= VT_VECTOR
| VT_I4
;
829 variant
->vvalue
.vt_i4_vec
.vvector_elements
= elems
;
830 fill_int32_vec(ctx
, &variant
->vvalue
.vt_i4_vec
.vvector_data
, ivector
, elems
);
833 static void fill_string_vec(TALLOC_CTX
* ctx
,
834 struct wsp_cbasestoragevariant
*variant
,
835 const char **strings
, uint16_t elems
)
838 variant
->vvalue
.vt_lpwstr_v
.vvector_elements
= elems
;
839 variant
->vvalue
.vt_lpwstr_v
.vvector_data
= talloc_zero_array(ctx
,
843 for( i
= 0; i
< elems
; i
++ ) {
844 variant
->vvalue
.vt_lpwstr_v
.vvector_data
[ i
].value
= talloc_strdup(ctx
, strings
[ i
]);
848 static void fill_bstr_vec(TALLOC_CTX
*ctx
,
849 struct vt_bstr
**pvector
,
850 const char **strings
, uint16_t elems
)
853 struct vt_bstr
*vdata
= talloc_zero_array(ctx
, struct vt_bstr
, elems
);
855 for( i
= 0; i
< elems
; i
++ ) {
856 vdata
[ i
].value
= talloc_strdup(ctx
, strings
[ i
]);
861 void set_variant_bstr(TALLOC_CTX
*ctx
, struct wsp_cbasestoragevariant
*variant
,
862 const char *string_val
)
864 variant
->vtype
= VT_BSTR
;
865 variant
->vvalue
.vt_bstr
.value
= talloc_strdup(ctx
, string_val
);
868 void set_variant_lpwstr_vector(TALLOC_CTX
*ctx
,
869 struct wsp_cbasestoragevariant
*variant
,
870 const char **string_vals
, uint32_t elems
)
872 variant
->vtype
= VT_LPWSTR
| VT_VECTOR
;
873 fill_string_vec(ctx
, variant
, string_vals
, elems
);
876 void set_variant_array_bstr(TALLOC_CTX
*ctx
,
877 struct wsp_cbasestoragevariant
*variant
,
878 const char **string_vals
, uint16_t elems
)
880 variant
->vtype
= VT_BSTR
| VT_ARRAY
;
881 variant
->vvalue
.vt_bstr_array
.cdims
= 1;
882 variant
->vvalue
.vt_bstr_array
.ffeatures
= 0;
884 variant
->vvalue
.vt_bstr_array
.rgsabound
=
885 talloc_zero_array(ctx
, struct safearraybound
, 1);
887 variant
->vvalue
.vt_bstr_array
.rgsabound
[0].celements
= elems
;
888 variant
->vvalue
.vt_bstr_array
.rgsabound
[0].ilbound
= 0;
889 variant
->vvalue
.vt_bstr_array
.cbelements
= 0;
890 fill_bstr_vec(ctx
, &variant
->vvalue
.vt_bstr_array
.vdata
,
893 * if cbelements is the num bytes per elem it kindof means each
894 * string in the array must be the same size ?
898 variant
->vvalue
.vt_bstr_array
.cbelements
=
899 strlen_m_term(variant
->vvalue
.vt_bstr_array
.vdata
[0].value
)*2;
903 /* create single dim array of vt_i4 */
904 void set_variant_array_i4(TALLOC_CTX
*ctx
,
905 struct wsp_cbasestoragevariant
*variant
,
906 int32_t *vals
, uint16_t elems
)
908 /* #TODO see if we can combine with other set_variant_array methods */
909 variant
->vtype
= VT_I4
| VT_ARRAY
;
910 variant
->vvalue
.vt_i4_array
.cdims
= 1;
911 variant
->vvalue
.vt_i4_array
.ffeatures
= 0;
913 variant
->vvalue
.vt_i4_array
.rgsabound
=
914 talloc_zero_array(ctx
, struct safearraybound
, 1);
916 variant
->vvalue
.vt_i4_array
.rgsabound
[0].celements
= elems
;
917 variant
->vvalue
.vt_i4_array
.rgsabound
[0].ilbound
= 0;
918 variant
->vvalue
.vt_i4_array
.cbelements
= sizeof(uint32_t);
919 fill_int32_vec(ctx
, &variant
->vvalue
.vt_i4_array
.vdata
, vals
, elems
);