/*
* Unix SMB/CIFS implementation.
* 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 .
*/
#include "includes.h"
#include
#include
#include
#include "lib/cmdline/cmdline.h"
#include "libcli/util/ntstatus.h"
#include "lib/util/samba_util.h"
#include "lib/torture/torture.h"
#include "lib/param/param.h"
#include "libcli/wsp/wsp_aqs.h"
#include "bin/default/librpc/gen_ndr/ndr_wsp.h"
#include "librpc/wsp/wsp_util.h"
/*
* some routines to help stringify the parsed AQS
* query so we can test parsing
*/
static bool is_operator_node(t_query *node)
{
if (node->type == eVALUE) {
return false;
}
return true;
}
static const char *nodetype_as_string(t_nodetype node)
{
const char *result = NULL;
switch (node) {
case eNOT:
result = "NOT";
break;
case eAND:
result = "AND";
break;
case eOR:
result = "OR";
break;
case eVALUE:
default:
break;
}
return result;
}
static const char *restriction_as_string(TALLOC_CTX *ctx,
struct wsp_crestriction *crestriction )
{
const char *result = NULL;
if (crestriction->ultype == RTPROPERTY) {
struct wsp_cpropertyrestriction *prop_restr =
&crestriction->restriction.cpropertyrestriction;
struct wsp_cbasestoragevariant *value = &prop_restr->prval;
result = variant_as_string(ctx, value, true);
} else {
struct wsp_ccontentrestriction *cont_restr = NULL;
cont_restr = &crestriction->restriction.ccontentrestriction;
result = talloc_strdup(ctx, cont_restr->pwcsphrase);
}
return result;
}
static const char *prop_name_from_restriction(
TALLOC_CTX *ctx,
struct wsp_crestriction *restriction)
{
const char *result = NULL;
struct wsp_cfullpropspec *prop;
if (restriction->ultype == RTCONTENT) {
prop = &restriction->restriction.ccontentrestriction.property;
} else {
prop = &restriction->restriction.cpropertyrestriction.property;
}
result = prop_from_fullprop(ctx, prop);
return result;
}
static char *print_basic_query(TALLOC_CTX *ctx,
struct wsp_crestriction *restriction)
{
const char *op_str = op_as_string(restriction);
const char *val_str = restriction_as_string(ctx, restriction);
const char *prop_name = prop_name_from_restriction(ctx, restriction);
char *res = talloc_asprintf(ctx,
"%s %s %s", prop_name, op_str ? op_str : "", val_str);
return res;
}
static char *print_node(TALLOC_CTX *ctx, t_query *node, bool is_rpn)
{
switch(node->type) {
case eAND:
case eOR:
case eNOT:
return talloc_asprintf(ctx,
" %s ", nodetype_as_string(node->type));
break;
case eVALUE:
default:
return print_basic_query(ctx, node->restriction);
break;
}
}
/*
* Algorithm infix (tree)
* Print the infix expression for an expression tree.
* Pre : tree is a pointer to an expression tree
* Post: the infix expression has been printed
* start infix
* if (tree not empty)
* if (tree token is operator)
* print (open parenthesis)
* end if
* infix (tree left subtree)
* print (tree token)
* infix (tree right subtree)
* if (tree token is operator)
* print (close parenthesis)
* end if
* end if
* end infix
*/
static char *infix(TALLOC_CTX *ctx, t_query *tree)
{
char *sresult = NULL;
char *stree = NULL;
char *sleft = NULL;
char *sright = NULL;
if (tree == NULL) {
return NULL;
}
if (is_operator_node(tree)) {
sresult = talloc_strdup(ctx, "(");
SMB_ASSERT(sresult != NULL);
}
sleft = infix(ctx, tree->left);
stree = print_node(ctx, tree, false);
sright = infix(ctx, tree->right);
sresult = talloc_asprintf(ctx, "%s%s%s%s",
sresult ? sresult : "",
sleft ? sleft : "",
stree? stree : "",
sright ? sright : "");
if (is_operator_node(tree)) {
sresult = talloc_asprintf(ctx, "%s)", sresult);
SMB_ASSERT(sresult != NULL);
}
return sresult;
}
static struct {
const char *aqs;
const char *stringified;
} no_col_map_queries [] = {
/* equals (numeric) */
{
"System.Size:10241",
"System.Size = 10241"
},
{
"System.Size := 10241",
"System.Size = 10241"
},
/* not equals */
{
"System.Size:!=10241",
"System.Size != 10241"
},
/* equals (string property) */
{
"ALL:(somestring)",
"All = 'somestring'"
},
{
"ALL:=somestring",
"All = 'somestring'"
},
{
"ALL:somestring",
"All = 'somestring'"
},
/* not equals (string) */
{
"ALL:!=somestring",
"All != 'somestring'"
},
/* Greater than */
{
"System.Size:(>10241)",
"System.Size > 10241"
},
{
"System.Size:>10241",
"System.Size > 10241"
},
/* Less than */
{
"System.Size:(<10241)",
"System.Size < 10241"
},
/* Greater than or equals */
{
"System.Size:(>=10241)",
"System.Size >= 10241"
},
{
"System.Size:>=10241",
"System.Size >= 10241"
},
/* Less than or equals */
{
"System.Size:(<=10241)",
"System.Size <= 10241"
},
{
"System.Size:<=10241",
"System.Size <= 10241"
},
/* equals (in the sense of matches) */
{
"ALL:($=somestring)",
"All equals somestring"
},
/* starts with */
{
"ALL:($= 10241 AND System.Size < 102401)"
},
{
"System.Size:small",
"(System.Size >= 10241 AND System.Size < 102401)"
},
/* NOT */
{
"NOT System.Size:10241",
"( NOT System.Size = 10241)"
},
/* AND */
{
"System.Size:(>=10241) AND System.Size:(<102401)",
"(System.Size >= 10241 AND System.Size < 102401)"
},
/* OR */
{
"System.Kind:picture OR System.Kind:video",
"(System.Kind = 'picture' OR System.Kind = 'video')"
},
/* MULTIPLE LOGICAL */
{
"System.Kind:picture AND NOT System.Kind:video OR "
"System.Kind:movie",
"(System.Kind = 'picture' AND (( NOT System.Kind = 'video') OR "
"System.Kind = 'movie'))"
},
/* parenthesized MULTIPLE LOGICAL */
{
"(System.Kind:picture AND NOT System.Kind:video) OR "
"System.Kind:movie",
"((System.Kind = 'picture' AND ( NOT System.Kind = 'video')) "
"OR System.Kind = 'movie')"
},
};
static char *dump_cols(TALLOC_CTX *ctx, t_select_stmt *select)
{
t_col_list *cols = select->cols;
char *res = NULL;
if (cols) {
int i;
for (i = 0; i < cols->num_cols; i++) {
if (i == 0) {
res = talloc_strdup(ctx,
cols->cols[i]);
} else {
res = talloc_asprintf(ctx,
"%s, %s",
res, cols->cols[i]);
}
}
}
return res;
}
static void test_wsp_parser(void **state)
{
int i;
t_select_stmt *select_stmt = NULL;
const char *col_query =
"SELECT System.ItemName, System.ItemURL, System.Size WHERE "
"System.Kind:picture";
char *res = NULL;
TALLOC_CTX *frame = talloc_stackframe();
for (i = 0; i < ARRAY_SIZE(no_col_map_queries); i++) {
select_stmt = get_wsp_sql_tree(no_col_map_queries[i].aqs);
assert_non_null(select_stmt);
assert_null(select_stmt->cols);
res = infix(frame, select_stmt->where);
DBG_DEBUG("reading query => %s parsed => %s\n",
no_col_map_queries[i].aqs,
res);
assert_string_equal(res, no_col_map_queries[i].stringified);
}
select_stmt = get_wsp_sql_tree(col_query);
res = infix(frame, select_stmt->where);
assert_string_equal(res, "System.Kind = 'picture'");
assert_non_null(select_stmt->cols);
res = dump_cols(frame, select_stmt);
assert_string_equal(res,
"System.ItemName, System.ItemURL, System.Size");
TALLOC_FREE(frame);
}
int main(int argc, const char *argv[])
{
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_wsp_parser),
};
struct poptOption long_options[] = {
POPT_AUTOHELP
POPT_COMMON_SAMBA
POPT_TABLEEND
};
poptContext pc;
int opt;
bool ok;
struct loadparm_context *lp_ctx = NULL;
TALLOC_CTX *frame = talloc_stackframe();
smb_init_locale();
ok = samba_cmdline_init(frame,
SAMBA_CMDLINE_CONFIG_CLIENT,
false /* require_smbconf */);
if (!ok) {
DBG_ERR("Failed to init cmdline parser!\n");
TALLOC_FREE(frame);
exit(1);
}
lp_ctx = samba_cmdline_get_lp_ctx();
if (!lp_ctx) {
DBG_ERR("Failed to init cmdline parser!\n");
TALLOC_FREE(frame);
exit(1);
}
lpcfg_set_cmdline(lp_ctx, "log level", "1");
pc = samba_popt_get_context(getprogname(),
argc,
argv,
long_options,
0);
if (pc == NULL) {
DBG_ERR("Failed to setup popt context!\n");
TALLOC_FREE(frame);
exit(1);
}
while ((opt = poptGetNextOpt(pc)) != -1) {
switch(opt) {
default:
fprintf(stderr, "Unknown Option: %c\n", opt);
exit(1);
}
}
cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
return cmocka_run_group_tests(tests, NULL, NULL);
}