wbemprox: Support IClientSecurity on the class enumerator object;.
[wine] / dlls / wbemprox / query.c
1 /*
2  * Copyright 2012 Hans Leidekker for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #define COBJMACROS
20
21 #include "config.h"
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wbemcli.h"
27
28 #include "wine/debug.h"
29 #include "wbemprox_private.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
32
33 static HRESULT get_column_index( const struct table *table, const WCHAR *name, UINT *column )
34 {
35     UINT i;
36     for (i = 0; i < table->num_cols; i++)
37     {
38         if (!strcmpiW( table->columns[i].name, name ))
39         {
40             *column = i;
41             return S_OK;
42         }
43     }
44     return WBEM_E_INVALID_QUERY;
45 }
46
47 static UINT get_column_size( const struct table *table, UINT column )
48 {
49     if (table->columns[column].type & CIM_FLAG_ARRAY) return sizeof(void *);
50
51     switch (table->columns[column].type & COL_TYPE_MASK)
52     {
53     case CIM_SINT16:
54     case CIM_UINT16:
55         return sizeof(INT16);
56     case CIM_SINT32:
57     case CIM_UINT32:
58         return sizeof(INT32);
59     case CIM_SINT64:
60     case CIM_UINT64:
61         return sizeof(INT64);
62     case CIM_DATETIME:
63     case CIM_STRING:
64         return sizeof(WCHAR *);
65     default:
66         ERR("unkown column type %u\n", table->columns[column].type & COL_TYPE_MASK);
67         break;
68     }
69     return sizeof(INT32);
70 }
71
72 static UINT get_column_offset( const struct table *table, UINT column )
73 {
74     UINT i, offset = 0;
75     for (i = 0; i < column; i++) offset += get_column_size( table, i );
76     return offset;
77 }
78
79 static UINT get_row_size( const struct table *table )
80 {
81     return get_column_offset( table, table->num_cols - 1 ) + get_column_size( table, table->num_cols - 1 );
82 }
83
84 static HRESULT get_value( const struct table *table, UINT row, UINT column, LONGLONG *val )
85 {
86     UINT col_offset, row_size;
87     const BYTE *ptr;
88
89     col_offset = get_column_offset( table, column );
90     row_size = get_row_size( table );
91     ptr = table->data + row * row_size + col_offset;
92
93     if (table->columns[column].type & CIM_FLAG_ARRAY)
94     {
95         *val = (LONGLONG)(INT_PTR)*(const void **)ptr;
96         return S_OK;
97     }
98     switch (table->columns[column].type & COL_TYPE_MASK)
99     {
100     case CIM_DATETIME:
101     case CIM_STRING:
102         *val = (LONGLONG)(INT_PTR)*(const WCHAR **)ptr;
103         break;
104     case CIM_SINT16:
105         *val = *(const INT16 *)ptr;
106         break;
107     case CIM_UINT16:
108         *val = *(const UINT16 *)ptr;
109         break;
110     case CIM_SINT32:
111         *val = *(const INT32 *)ptr;
112         break;
113     case CIM_UINT32:
114         *val = *(const UINT32 *)ptr;
115         break;
116     case CIM_SINT64:
117         *val = *(const INT64 *)ptr;
118         break;
119     case CIM_UINT64:
120         *val = *(const UINT64 *)ptr;
121         break;
122     default:
123         ERR("invalid column type %u\n", table->columns[column].type & COL_TYPE_MASK);
124         *val = 0;
125         break;
126     }
127     return S_OK;
128 }
129
130 static BSTR get_value_bstr( const struct table *table, UINT row, UINT column )
131 {
132     static const WCHAR fmt_signedW[] = {'%','d',0};
133     static const WCHAR fmt_unsignedW[] = {'%','u',0};
134     static const WCHAR fmt_signed64W[] = {'%','I','6','4','d',0};
135     static const WCHAR fmt_unsigned64W[] = {'%','I','6','4','u',0};
136     static const WCHAR fmt_strW[] = {'\"','%','s','\"',0};
137     LONGLONG val;
138     BSTR ret;
139     WCHAR number[22];
140     UINT len;
141
142     if (table->columns[column].type & CIM_FLAG_ARRAY)
143     {
144         FIXME("array to string conversion not handled\n");
145         return NULL;
146     }
147     if (get_value( table, row, column, &val ) != S_OK) return NULL;
148
149     switch (table->columns[column].type & COL_TYPE_MASK)
150     {
151     case CIM_DATETIME:
152     case CIM_STRING:
153         len = strlenW( (const WCHAR *)(INT_PTR)val ) + 2;
154         if (!(ret = SysAllocStringLen( NULL, len ))) return NULL;
155         sprintfW( ret, fmt_strW, (const WCHAR *)(INT_PTR)val );
156         return ret;
157
158     case CIM_SINT16:
159     case CIM_SINT32:
160         sprintfW( number, fmt_signedW, val );
161         return SysAllocString( number );
162
163     case CIM_UINT16:
164     case CIM_UINT32:
165         sprintfW( number, fmt_unsignedW, val );
166         return SysAllocString( number );
167
168     case CIM_SINT64:
169         wsprintfW( number, fmt_signed64W, val );
170         return SysAllocString( number );
171
172     case CIM_UINT64:
173         wsprintfW( number, fmt_unsigned64W, val );
174         return SysAllocString( number );
175
176     default:
177         FIXME("unhandled column type %u\n", table->columns[column].type & COL_TYPE_MASK);
178         break;
179     }
180     return NULL;
181 }
182
183 HRESULT create_view( const struct property *proplist, const WCHAR *class,
184                      const struct expr *cond, struct view **ret )
185 {
186     struct view *view = heap_alloc( sizeof(struct view) );
187
188     if (!view) return E_OUTOFMEMORY;
189     view->proplist = proplist;
190     view->table    = get_table( class );
191     view->cond     = cond;
192     view->result   = NULL;
193     view->count    = 0;
194     *ret = view;
195     return S_OK;
196 }
197
198 static void clear_table( struct table *table )
199 {
200     UINT i, j, type;
201
202     if (!table->fill || !table->data) return;
203
204     for (i = 0; i < table->num_rows; i++)
205     {
206         for (j = 0; j < table->num_cols; j++)
207         {
208             if (!(table->columns[j].type & COL_FLAG_DYNAMIC)) continue;
209
210             type = table->columns[j].type & COL_TYPE_MASK;
211             if (type == CIM_STRING || type == CIM_DATETIME || (type & CIM_FLAG_ARRAY))
212             {
213                 void *ptr;
214                 if (get_value( table, i, j, (LONGLONG *)&ptr ) == S_OK) heap_free( ptr );
215             }
216         }
217     }
218     heap_free( table->data );
219     table->data = NULL;
220 }
221
222 void destroy_view( struct view *view )
223 {
224     if (view->table) clear_table( view->table );
225     heap_free( view->result );
226     heap_free( view );
227 }
228
229 static BOOL eval_like( LONGLONG lval, LONGLONG rval )
230 {
231     const WCHAR *p = (const WCHAR *)(INT_PTR)lval, *q = (const WCHAR *)(INT_PTR)rval;
232
233     while (*p && *q)
234     {
235         if (*q == '%')
236         {
237             while (*q == '%') q++;
238             if (!*q) return TRUE;
239             while (*p && toupperW( p[1] ) != toupperW( q[1] )) p++;
240             if (!*p) return TRUE;
241         }
242         if (toupperW( *p++ ) != toupperW( *q++ )) return FALSE;
243     }
244     return TRUE;
245 }
246
247 static HRESULT eval_cond( const struct table *, UINT, const struct expr *, LONGLONG * );
248
249 static BOOL eval_binary( const struct table *table, UINT row, const struct complex_expr *expr,
250                          LONGLONG *val )
251 {
252     HRESULT lret, rret;
253     LONGLONG lval, rval;
254
255     lret = eval_cond( table, row, expr->left, &lval );
256     rret = eval_cond( table, row, expr->right, &rval );
257     if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY;
258
259     switch (expr->op)
260     {
261     case OP_EQ:
262         *val = (lval == rval);
263         break;
264     case OP_AND:
265         *val = (lval && rval);
266         break;
267     case OP_OR:
268         *val = (lval || rval);
269         break;
270     case OP_GT:
271         *val = (lval > rval);
272         break;
273     case OP_LT:
274         *val = (lval < rval);
275         break;
276     case OP_LE:
277         *val = (lval <= rval);
278         break;
279     case OP_GE:
280         *val = (lval >= rval);
281         break;
282     case OP_NE:
283         *val = (lval != rval);
284         break;
285     case OP_LIKE:
286         *val = eval_like( lval, rval );
287         break;
288     default:
289         ERR("unknown operator %u\n", expr->op);
290         return WBEM_E_INVALID_QUERY;
291     }
292     return S_OK;
293 }
294
295 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr,
296                            LONGLONG *val )
297
298 {
299     HRESULT hr;
300     UINT column;
301     LONGLONG lval;
302
303     hr = get_column_index( table, expr->left->u.propval->name, &column );
304     if (hr != S_OK)
305         return hr;
306
307     hr = get_value( table, row, column, &lval );
308     if (hr != S_OK)
309         return hr;
310
311     switch (expr->op)
312     {
313     case OP_ISNULL:
314         *val = !lval;
315         break;
316     case OP_NOTNULL:
317         *val = lval;
318         break;
319     default:
320         ERR("unknown operator %u\n", expr->op);
321         return WBEM_E_INVALID_QUERY;
322     }
323     return S_OK;
324 }
325
326 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval,
327                              LONGLONG *val )
328
329 {
330     HRESULT hr;
331     UINT column;
332
333     hr = get_column_index( table, propval->name, &column );
334     if (hr != S_OK)
335         return hr;
336
337     return get_value( table, row, column, val );
338 }
339
340 static HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond,
341                           LONGLONG *val )
342 {
343     if (!cond)
344     {
345         *val = 1;
346         return S_OK;
347     }
348     switch (cond->type)
349     {
350     case EXPR_COMPLEX:
351         return eval_binary( table, row, &cond->u.expr, val );
352     case EXPR_UNARY:
353         return eval_unary( table, row, &cond->u.expr, val );
354     case EXPR_PROPVAL:
355         return eval_propval( table, row, cond->u.propval, val );
356     case EXPR_SVAL:
357         *val = (LONGLONG)(INT_PTR)cond->u.sval;
358         return S_OK;
359     case EXPR_IVAL:
360     case EXPR_BVAL:
361         *val = cond->u.ival;
362         return S_OK;
363     default:
364         ERR("invalid expression type\n");
365         break;
366     }
367     return WBEM_E_INVALID_QUERY;
368 }
369
370 static HRESULT execute_view( struct view *view )
371 {
372     UINT i, j = 0, len;
373
374     if (!view->table || !view->table->num_rows) return S_OK;
375
376     len = min( view->table->num_rows, 16 );
377     if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
378
379     for (i = 0; i < view->table->num_rows; i++)
380     {
381         HRESULT hr;
382         LONGLONG val = 0;
383
384         if (j >= len)
385         {
386             UINT *tmp;
387             len *= 2;
388             if (!(tmp = heap_realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY;
389             view->result = tmp;
390         }
391         if ((hr = eval_cond( view->table, i, view->cond, &val )) != S_OK) return hr;
392         if (val) view->result[j++] = i;
393     }
394     view->count = j;
395     return S_OK;
396 }
397
398 static struct query *alloc_query(void)
399 {
400     struct query *query;
401
402     if (!(query = heap_alloc( sizeof(*query) ))) return NULL;
403     list_init( &query->mem );
404     return query;
405 }
406
407 void free_query( struct query *query )
408 {
409     struct list *mem, *next;
410
411     destroy_view( query->view );
412     LIST_FOR_EACH_SAFE( mem, next, &query->mem )
413     {
414         heap_free( mem );
415     }
416     heap_free( query );
417 }
418
419 HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result )
420 {
421     HRESULT hr;
422     struct query *query;
423
424     *result = NULL;
425     if (!(query = alloc_query())) return E_OUTOFMEMORY;
426     hr = parse_query( str, &query->view, &query->mem );
427     if (hr != S_OK) goto done;
428     hr = execute_view( query->view );
429     if (hr != S_OK) goto done;
430     hr = EnumWbemClassObject_create( NULL, query, (void **)result );
431
432 done:
433     if (hr != S_OK) free_query( query );
434     return hr;
435 }
436
437 static BOOL is_selected_prop( const struct view *view, const WCHAR *name )
438 {
439     const struct property *prop = view->proplist;
440
441     if (!prop) return TRUE;
442     while (prop)
443     {
444         if (!strcmpiW( prop->name, name )) return TRUE;
445         prop = prop->next;
446     }
447     return FALSE;
448 }
449
450 static BOOL is_system_prop( const WCHAR *name )
451 {
452     return (name[0] == '_' && name[1] == '_');
453 }
454
455 static BSTR build_servername( const struct view *view )
456 {
457     WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
458     DWORD len = sizeof(server)/sizeof(server[0]);
459
460     if (view->proplist) return NULL;
461
462     if (!(GetComputerNameW( server, &len ))) return NULL;
463     for (p = server; *p; p++) *p = toupperW( *p );
464     return SysAllocString( server );
465 }
466
467 static BSTR build_classname( const struct view *view )
468 {
469     return SysAllocString( view->table->name );
470 }
471
472 static BSTR build_namespace( const struct view *view )
473 {
474     static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0};
475
476     if (view->proplist) return NULL;
477     return SysAllocString( cimv2W );
478 }
479
480 static BSTR build_proplist( const struct view *view, UINT index, UINT count, UINT *len )
481 {
482     static const WCHAR fmtW[] = {'%','s','=','%','s',0};
483     UINT i, j, offset, row = view->result[index];
484     BSTR *values, ret = NULL;
485
486     if (!(values = heap_alloc( count * sizeof(BSTR) ))) return NULL;
487
488     *len = j = 0;
489     for (i = 0; i < view->table->num_cols; i++)
490     {
491         if (view->table->columns[i].type & COL_FLAG_KEY)
492         {
493             const WCHAR *name = view->table->columns[i].name;
494
495             values[j] = get_value_bstr( view->table, row, i );
496             *len += strlenW( fmtW ) + strlenW( name ) + strlenW( values[j] );
497             j++;
498         }
499     }
500     if ((ret = SysAllocStringLen( NULL, *len )))
501     {
502         offset = j = 0;
503         for (i = 0; i < view->table->num_cols; i++)
504         {
505             if (view->table->columns[i].type & COL_FLAG_KEY)
506             {
507                 const WCHAR *name = view->table->columns[i].name;
508
509                 offset += sprintfW( ret + offset, fmtW, name, values[j] );
510                 if (j < count - 1) ret[offset++] = ',';
511                 j++;
512             }
513         }
514     }
515     for (i = 0; i < count; i++) SysFreeString( values[i] );
516     heap_free( values );
517     return ret;
518 }
519
520 static UINT count_key_columns( const struct view *view )
521 {
522     UINT i, num_keys = 0;
523
524     for (i = 0; i < view->table->num_cols; i++)
525     {
526         if (view->table->columns[i].type & COL_FLAG_KEY) num_keys++;
527     }
528     return num_keys;
529 }
530
531 static BSTR build_relpath( const struct view *view, UINT index, const WCHAR *name )
532 {
533     static const WCHAR fmtW[] = {'%','s','.','%','s',0};
534     BSTR class, proplist, ret = NULL;
535     UINT num_keys, len;
536
537     if (view->proplist) return NULL;
538
539     if (!(class = build_classname( view ))) return NULL;
540     if (!(num_keys = count_key_columns( view ))) return class;
541     if (!(proplist = build_proplist( view, index, num_keys, &len ))) goto done;
542
543     len += strlenW( fmtW ) + SysStringLen( class );
544     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
545     sprintfW( ret, fmtW, class, proplist );
546
547 done:
548     SysFreeString( class );
549     SysFreeString( proplist );
550     return ret;
551 }
552
553 static BSTR build_path( const struct view *view, UINT index, const WCHAR *name )
554 {
555     static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':','%','s',0};
556     BSTR server, namespace = NULL, relpath = NULL, ret = NULL;
557     UINT len;
558
559     if (view->proplist) return NULL;
560
561     if (!(server = build_servername( view ))) return NULL;
562     if (!(namespace = build_namespace( view ))) goto done;
563     if (!(relpath = build_relpath( view, index, name ))) goto done;
564
565     len = strlenW( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath );
566     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
567     sprintfW( ret, fmtW, server, namespace, relpath );
568
569 done:
570     SysFreeString( server );
571     SysFreeString( namespace );
572     SysFreeString( relpath );
573     return ret;
574 }
575
576 static UINT count_selected_props( const struct view *view )
577 {
578     const struct property *prop = view->proplist;
579     UINT count;
580
581     if (!prop) return view->table->num_cols;
582
583     count = 1;
584     while ((prop = prop->next)) count++;
585     return count;
586 }
587
588 static HRESULT get_system_propval( const struct view *view, UINT index, const WCHAR *name,
589                                    VARIANT *ret, CIMTYPE *type )
590 {
591     static const WCHAR classW[] = {'_','_','C','L','A','S','S',0};
592     static const WCHAR genusW[] = {'_','_','G','E','N','U','S',0};
593     static const WCHAR pathW[] = {'_','_','P','A','T','H',0};
594     static const WCHAR namespaceW[] = {'_','_','N','A','M','E','S','P','A','C','E',0};
595     static const WCHAR propcountW[] = {'_','_','P','R','O','P','E','R','T','Y','_','C','O','U','N','T',0};
596     static const WCHAR relpathW[] = {'_','_','R','E','L','P','A','T','H',0};
597     static const WCHAR serverW[] = {'_','_','S','E','R','V','E','R',0};
598
599     if (!strcmpiW( name, classW ))
600     {
601         V_VT( ret ) = VT_BSTR;
602         V_BSTR( ret ) = build_classname( view );
603         if (type) *type = CIM_STRING;
604         return S_OK;
605     }
606     if (!strcmpiW( name, genusW ))
607     {
608         V_VT( ret ) = VT_INT;
609         V_INT( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */
610         if (type) *type = CIM_SINT32;
611         return S_OK;
612     }
613     else if (!strcmpiW( name, namespaceW ))
614     {
615         V_VT( ret ) = VT_BSTR;
616         V_BSTR( ret ) = build_namespace( view );
617         if (type) *type = CIM_STRING;
618         return S_OK;
619     }
620     else if (!strcmpiW( name, pathW ))
621     {
622         V_VT( ret ) = VT_BSTR;
623         V_BSTR( ret ) = build_path( view, index, name );
624         if (type) *type = CIM_STRING;
625         return S_OK;
626     }
627     if (!strcmpiW( name, propcountW ))
628     {
629         V_VT( ret ) = VT_INT;
630         V_INT( ret ) = count_selected_props( view );
631         if (type) *type = CIM_SINT32;
632         return S_OK;
633     }
634     else if (!strcmpiW( name, relpathW ))
635     {
636         V_VT( ret ) = VT_BSTR;
637         V_BSTR( ret ) = build_relpath( view, index, name );
638         if (type) *type = CIM_STRING;
639         return S_OK;
640     }
641     else if (!strcmpiW( name, serverW ))
642     {
643         V_VT( ret ) = VT_BSTR;
644         V_BSTR( ret ) = build_servername( view );
645         if (type) *type = CIM_STRING;
646         return S_OK;
647     }
648     FIXME("system property %s not implemented\n", debugstr_w(name));
649     return WBEM_E_NOT_FOUND;
650 }
651
652 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret, CIMTYPE *type )
653 {
654     HRESULT hr;
655     UINT column, row = view->result[index];
656     LONGLONG val;
657
658     if (is_system_prop( name )) return get_system_propval( view, index, name, ret, type );
659     if (!is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
660
661     hr = get_column_index( view->table, name, &column );
662     if (hr != S_OK) return WBEM_E_NOT_FOUND;
663
664     hr = get_value( view->table, row, column, &val );
665     if (hr != S_OK) return hr;
666
667     switch (view->table->columns[column].type & COL_TYPE_MASK)
668     {
669     case CIM_STRING:
670     case CIM_DATETIME:
671         V_VT( ret ) = VT_BSTR;
672         V_BSTR( ret ) = SysAllocString( (const WCHAR *)(INT_PTR)val );
673         break;
674     case CIM_SINT16:
675         V_VT( ret ) = VT_I2;
676         V_I2( ret ) = val;
677         break;
678     case CIM_UINT16:
679         V_VT( ret ) = VT_UI2;
680         V_UI2( ret ) = val;
681         break;
682     case CIM_SINT32:
683         V_VT( ret ) = VT_I4;
684         V_I4( ret ) = val;
685         break;
686     case CIM_UINT32:
687         V_VT( ret ) = VT_UI4;
688         V_UI4( ret ) = val;
689         break;
690     case CIM_SINT64:
691         V_VT( ret ) = VT_I8;
692         V_I8( ret ) = val;
693         break;
694     case CIM_UINT64:
695         V_VT( ret ) = VT_UI8;
696         V_UI8( ret ) = val;
697         break;
698     default:
699         ERR("unhandled column type %u\n", view->table->columns[column].type);
700         return WBEM_E_FAILED;
701     }
702     if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
703     return S_OK;
704 }
705
706 HRESULT get_properties( const struct view *view, SAFEARRAY **props )
707 {
708     SAFEARRAY *sa;
709     BSTR str;
710     LONG i;
711
712     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, view->table->num_cols ))) return E_OUTOFMEMORY;
713
714     for (i = 0; i < view->table->num_cols; i++)
715     {
716         str = SysAllocString( view->table->columns[i].name );
717         if (!str || SafeArrayPutElement( sa, &i, str ) != S_OK)
718         {
719             SysFreeString( str );
720             SafeArrayDestroy( sa );
721             return E_OUTOFMEMORY;
722         }
723     }
724     *props = sa;
725     return S_OK;
726 }