2005-01-30 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-marshal-validate.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-marshal-validate.c Validation routines for marshaled data
3  *
4  * Copyright (C) 2005 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
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 2 of the License, or
11  * (at your option) any later version.
12  *
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.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-internals.h"
25 #include "dbus-marshal-validate.h"
26 #include "dbus-marshal-recursive.h"
27 #include "dbus-marshal-basic.h"
28 #include "dbus-string.h"
29
30 /**
31  * @addtogroup DBusMarshal
32  *
33  * @{
34  */
35
36 /**
37  * Verifies that the range of type_str from type_pos to type_end is a
38  * valid signature.  If this function returns #TRUE, it will be safe
39  * to iterate over the signature with a types-only #DBusTypeReader.
40  * The range passed in should NOT include the terminating
41  * nul/DBUS_TYPE_INVALID.
42  *
43  * @todo verify that dict entries have exactly two fields
44  * 
45  * @todo require that dict entries are in an array
46  *
47  * @param type_str the string
48  * @param type_pos where the typecodes start
49  * @param len length of typecodes
50  * @returns #DBUS_VALID if valid, reason why invalid otherwise
51  */
52 DBusValidity
53 _dbus_validate_signature_with_reason (const DBusString *type_str,
54                                       int               type_pos,
55                                       int               len)
56 {
57   const unsigned char *p;
58   const unsigned char *end;
59   int last;
60   int struct_depth;
61   int array_depth;
62   int dict_entry_depth;
63
64   _dbus_assert (type_str != NULL);
65   _dbus_assert (type_pos < _DBUS_INT32_MAX - len);
66   _dbus_assert (len >= 0);
67   _dbus_assert (type_pos >= 0);
68
69   if (len > DBUS_MAXIMUM_SIGNATURE_LENGTH)
70     return DBUS_INVALID_SIGNATURE_TOO_LONG;
71
72   p = _dbus_string_get_const_data_len (type_str, type_pos, 0);
73   end = _dbus_string_get_const_data_len (type_str, type_pos + len, 0);
74   struct_depth = 0;
75   array_depth = 0;
76   dict_entry_depth = 0;
77   last = DBUS_TYPE_INVALID;
78
79   while (p != end)
80     {
81       switch (*p)
82         {
83         case DBUS_TYPE_BYTE:
84         case DBUS_TYPE_BOOLEAN:
85         case DBUS_TYPE_INT16:
86         case DBUS_TYPE_UINT16:
87         case DBUS_TYPE_INT32:
88         case DBUS_TYPE_UINT32:
89         case DBUS_TYPE_INT64:
90         case DBUS_TYPE_UINT64:
91         case DBUS_TYPE_DOUBLE:
92         case DBUS_TYPE_STRING:
93         case DBUS_TYPE_OBJECT_PATH:
94         case DBUS_TYPE_SIGNATURE:
95         case DBUS_TYPE_VARIANT:
96           break;
97
98         case DBUS_TYPE_ARRAY:
99           array_depth += 1;
100           if (array_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH)
101             return DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION;
102           break;
103
104         case DBUS_STRUCT_BEGIN_CHAR:
105           struct_depth += 1;
106
107           if (struct_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH)
108             return DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION;
109           break;
110
111         case DBUS_STRUCT_END_CHAR:
112           if (struct_depth == 0)
113             return DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED;
114
115           if (last == DBUS_STRUCT_BEGIN_CHAR)
116             return DBUS_INVALID_STRUCT_HAS_NO_FIELDS;
117
118           struct_depth -= 1;
119           break;
120
121         case DBUS_DICT_ENTRY_BEGIN_CHAR:
122           if (last != DBUS_TYPE_ARRAY)
123             return DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY;
124           
125           dict_entry_depth += 1;
126
127           if (dict_entry_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH)
128             return DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION;
129           break;
130
131         case DBUS_DICT_ENTRY_END_CHAR:
132           if (dict_entry_depth == 0)
133             return DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED;
134           
135           if (last == DBUS_DICT_ENTRY_BEGIN_CHAR)
136             return DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS;
137
138           dict_entry_depth -= 1;
139           break;
140           
141         case DBUS_TYPE_STRUCT:     /* doesn't appear in signatures */
142         case DBUS_TYPE_DICT_ENTRY: /* ditto */
143         default:
144           return DBUS_INVALID_UNKNOWN_TYPECODE;
145         }
146
147       if (*p != DBUS_TYPE_ARRAY)
148         array_depth = 0;
149
150       last = *p;
151       ++p;
152     }
153
154   if (array_depth > 0)
155     return DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE;
156
157   if (struct_depth > 0)
158     return DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED;
159
160   if (dict_entry_depth > 0)
161     return DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED;
162   
163   return DBUS_VALID;
164 }
165
166 static DBusValidity
167 validate_body_helper (DBusTypeReader       *reader,
168                       int                   byte_order,
169                       dbus_bool_t           walk_reader_to_end,
170                       const unsigned char  *p,
171                       const unsigned char  *end,
172                       const unsigned char **new_p)
173 {
174   int current_type;
175
176   while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
177     {
178       const unsigned char *a;
179       int alignment;
180
181 #if 0
182       _dbus_verbose ("   validating value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
183                      _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
184                      (int) (end - p));
185 #endif
186
187       /* Guarantee that p has one byte to look at */
188       if (p == end)
189         return DBUS_INVALID_NOT_ENOUGH_DATA;
190
191       switch (current_type)
192         {
193         case DBUS_TYPE_BYTE:
194           ++p;
195           break;
196           
197         case DBUS_TYPE_BOOLEAN:
198         case DBUS_TYPE_INT16:
199         case DBUS_TYPE_UINT16:
200         case DBUS_TYPE_INT32:
201         case DBUS_TYPE_UINT32:
202         case DBUS_TYPE_INT64:
203         case DBUS_TYPE_UINT64:
204         case DBUS_TYPE_DOUBLE:
205           alignment = _dbus_type_get_alignment (current_type);
206           a = _DBUS_ALIGN_ADDRESS (p, alignment);
207           if (a >= end)
208             return DBUS_INVALID_NOT_ENOUGH_DATA;
209           while (p != a)
210             {
211               if (*p != '\0')
212                 return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
213               ++p;
214             }
215           
216           if (current_type == DBUS_TYPE_BOOLEAN)
217             {
218               dbus_uint32_t v = _dbus_unpack_uint32 (byte_order,
219                                                      p);
220               if (!(v == 0 || v == 1))
221                 return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE;
222             }
223           
224           p += alignment;
225           break;
226
227         case DBUS_TYPE_ARRAY:
228         case DBUS_TYPE_STRING:
229         case DBUS_TYPE_OBJECT_PATH:
230           {
231             dbus_uint32_t claimed_len;
232
233             a = _DBUS_ALIGN_ADDRESS (p, 4);
234             if (a + 4 > end)
235               return DBUS_INVALID_NOT_ENOUGH_DATA;
236             while (p != a)
237               {
238                 if (*p != '\0')
239                   return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
240                 ++p;
241               }
242
243             claimed_len = _dbus_unpack_uint32 (byte_order, p);
244             p += 4;
245
246             /* p may now be == end */
247             _dbus_assert (p <= end);
248             
249             if (current_type == DBUS_TYPE_ARRAY)
250               {
251                 int array_elem_type = _dbus_type_reader_get_element_type (reader);
252                 alignment = _dbus_type_get_alignment (array_elem_type);
253                 p = _DBUS_ALIGN_ADDRESS (p, alignment);
254               }
255
256             if (claimed_len > (unsigned long) (end - p))
257               return DBUS_INVALID_STRING_LENGTH_OUT_OF_BOUNDS;
258
259             if (current_type == DBUS_TYPE_OBJECT_PATH)
260               {
261                 DBusString str;
262                 _dbus_string_init_const_len (&str, p, claimed_len);
263                 if (!_dbus_validate_path (&str, 0,
264                                           _dbus_string_get_length (&str)))
265                   return DBUS_INVALID_BAD_PATH;
266
267                 p += claimed_len;
268               }
269             else if (current_type == DBUS_TYPE_STRING)
270               {
271                 DBusString str;
272                 _dbus_string_init_const_len (&str, p, claimed_len);
273                 if (!_dbus_string_validate_utf8 (&str, 0,
274                                                  _dbus_string_get_length (&str)))
275                   return DBUS_INVALID_BAD_UTF8_IN_STRING;
276
277                 p += claimed_len;
278               }
279             else if (current_type == DBUS_TYPE_ARRAY && claimed_len > 0)
280               {
281                 DBusTypeReader sub;
282                 DBusValidity validity;
283                 const unsigned char *array_end;
284
285                 /* Remember that the reader is types only, so we can't
286                  * use it to iterate over elements. It stays the same
287                  * for all elements.
288                  */
289                 _dbus_type_reader_recurse (reader, &sub);
290
291                 array_end = p + claimed_len;
292
293                 while (p < array_end)
294                   {
295                     /* FIXME we are calling a function per array element! very bad
296                      * need if (dbus_type_is_fixed(elem_type)) here to just skip
297                      * big blocks of ints/bytes/etc.
298                      */                     
299                     
300                     validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
301                     if (validity != DBUS_VALID)
302                       return validity;
303                   }
304
305                 if (p != array_end)
306                   return DBUS_INVALID_ARRAY_LENGTH_INCORRECT;
307               }
308
309             /* check nul termination */
310             if (current_type != DBUS_TYPE_ARRAY)
311               {
312                 if (p == end)
313                   return DBUS_INVALID_NOT_ENOUGH_DATA;
314
315                 if (*p != '\0')
316                   return DBUS_INVALID_STRING_MISSING_NUL;
317                 ++p;
318               }
319           }
320           break;
321
322         case DBUS_TYPE_SIGNATURE:
323           {
324             dbus_uint32_t claimed_len;
325             DBusString str;
326
327             claimed_len = *p;
328             ++p;
329
330             /* 1 is for nul termination */
331             if (claimed_len + 1 > (unsigned long) (end - p))
332               return DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS;
333
334             _dbus_string_init_const_len (&str, p, claimed_len);
335             if (!_dbus_validate_signature (&str, 0,
336                                            _dbus_string_get_length (&str)))
337               return DBUS_INVALID_BAD_SIGNATURE;
338
339             p += claimed_len;
340
341             _dbus_assert (p < end);
342             if (*p != DBUS_TYPE_INVALID)
343               return DBUS_INVALID_SIGNATURE_MISSING_NUL;
344
345             ++p;
346
347             _dbus_verbose ("p = %p end = %p claimed_len %u\n", p, end, claimed_len);
348           }
349           break;
350
351         case DBUS_TYPE_VARIANT:
352           {
353             /* 1 byte sig len, sig typecodes, align to
354              * contained-type-boundary, values.
355              */
356
357             /* In addition to normal signature validation, we need to be sure
358              * the signature contains only a single (possibly container) type.
359              */
360             dbus_uint32_t claimed_len;
361             DBusString sig;
362             DBusTypeReader sub;
363             DBusValidity validity;
364             int contained_alignment;
365
366             claimed_len = *p;
367             ++p;
368
369             /* + 1 for nul */
370             if (claimed_len + 1 > (unsigned long) (end - p))
371               return DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS;
372
373             _dbus_string_init_const_len (&sig, p, claimed_len);
374             if (!_dbus_validate_signature (&sig, 0,
375                                            _dbus_string_get_length (&sig)))
376               return DBUS_INVALID_VARIANT_SIGNATURE_BAD;
377
378             p += claimed_len;
379
380             if (*p != DBUS_TYPE_INVALID)
381               return DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL;
382             ++p;
383
384             contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (&sig, 0));
385             
386             a = _DBUS_ALIGN_ADDRESS (p, contained_alignment);
387             if (a > end)
388               return DBUS_INVALID_NOT_ENOUGH_DATA;
389             while (p != a)
390               {
391                 if (*p != '\0')
392                   return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
393                 ++p;
394               }
395
396             _dbus_type_reader_init_types_only (&sub, &sig, 0);
397
398             if (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID)
399               return DBUS_INVALID_VARIANT_SIGNATURE_EMPTY;
400
401             validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
402             if (validity != DBUS_VALID)
403               return validity;
404
405             if (_dbus_type_reader_next (&sub))
406               return DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES;
407
408             _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID);
409           }
410           break;
411
412         case DBUS_TYPE_DICT_ENTRY:
413         case DBUS_TYPE_STRUCT:
414           {
415             DBusTypeReader sub;
416             DBusValidity validity;
417
418             a = _DBUS_ALIGN_ADDRESS (p, 8);
419             if (a > end)
420               return DBUS_INVALID_NOT_ENOUGH_DATA;
421             while (p != a)
422               {
423                 if (*p != '\0')
424                   return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
425                 ++p;
426               }
427
428             _dbus_type_reader_recurse (reader, &sub);
429
430             validity = validate_body_helper (&sub, byte_order, TRUE, p, end, &p);
431             if (validity != DBUS_VALID)
432               return validity;
433           }
434           break;
435
436         default:
437           _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature");
438           break;
439         }
440
441 #if 0
442       _dbus_verbose ("   validated value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
443                      _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
444                      (int) (end - p));
445 #endif
446
447       if (p > end)
448         {
449           _dbus_verbose ("not enough data!!! p = %p end = %p end-p = %d\n",
450                          p, end, (int) (end - p));
451           return DBUS_INVALID_NOT_ENOUGH_DATA;
452         }
453
454       if (walk_reader_to_end)
455         _dbus_type_reader_next (reader);
456       else
457         break;
458     }
459
460   if (new_p)
461     *new_p = p;
462
463   return DBUS_VALID;
464 }
465
466 /**
467  * Verifies that the range of value_str from value_pos to value_end is
468  * a legitimate value of type expected_signature.  If this function
469  * returns #TRUE, it will be safe to iterate over the values with
470  * #DBusTypeReader. The signature is assumed to be already valid.
471  *
472  * If bytes_remaining is not #NULL, then leftover bytes will be stored
473  * there and #DBUS_VALID returned. If it is #NULL, then
474  * #DBUS_INVALID_TOO_MUCH_DATA will be returned if bytes are left
475  * over.
476  *
477  * @param expected_signature the expected types in the value_str
478  * @param expected_signature_start where in expected_signature is the signature
479  * @param byte_order the byte order
480  * @param bytes_remaining place to store leftover bytes
481  * @param value_str the string containing the body
482  * @param value_pos where the values start
483  * @param len length of values after value_pos
484  * @returns #DBUS_VALID if valid, reason why invalid otherwise
485  */
486 DBusValidity
487 _dbus_validate_body_with_reason (const DBusString *expected_signature,
488                                  int               expected_signature_start,
489                                  int               byte_order,
490                                  int              *bytes_remaining,
491                                  const DBusString *value_str,
492                                  int               value_pos,
493                                  int               len)
494 {
495   DBusTypeReader reader;
496   const unsigned char *p;
497   const unsigned char *end;
498   DBusValidity validity;
499
500   _dbus_assert (len >= 0);
501   _dbus_assert (value_pos >= 0);
502   _dbus_assert (value_pos <= _dbus_string_get_length (value_str) - len);
503
504   _dbus_verbose ("validating body from pos %d len %d sig '%s'\n",
505                  value_pos, len, _dbus_string_get_const_data_len (expected_signature,
506                                                                   expected_signature_start,
507                                                                   0));
508
509   _dbus_type_reader_init_types_only (&reader,
510                                      expected_signature, expected_signature_start);
511
512   p = _dbus_string_get_const_data_len (value_str, value_pos, len);
513   end = p + len;
514
515   validity = validate_body_helper (&reader, byte_order, TRUE, p, end, &p);
516   if (validity != DBUS_VALID)
517     return validity;
518   
519   if (bytes_remaining)
520     {
521       *bytes_remaining = end - p;
522       return DBUS_VALID;
523     }
524   else if (p < end)
525     return DBUS_INVALID_TOO_MUCH_DATA;
526   else
527     {
528       _dbus_assert (p == end);
529       return DBUS_VALID;
530     }
531 }
532
533 /**
534  * Determine wether the given charater is valid as the first charater
535  * in a name.
536  */
537 #define VALID_INITIAL_NAME_CHARACTER(c)         \
538   ( ((c) >= 'A' && (c) <= 'Z') ||               \
539     ((c) >= 'a' && (c) <= 'z') ||               \
540     ((c) == '_') )
541
542 /**
543  * Determine wether the given charater is valid as a second or later
544  * character in a name
545  */
546 #define VALID_NAME_CHARACTER(c)                 \
547   ( ((c) >= '0' && (c) <= '9') ||               \
548     ((c) >= 'A' && (c) <= 'Z') ||               \
549     ((c) >= 'a' && (c) <= 'z') ||               \
550     ((c) == '_') )
551
552 /**
553  * Checks that the given range of the string is a valid object path
554  * name in the D-BUS protocol. Part of the validation ensures that
555  * the object path contains only ASCII.
556  *
557  * @todo this is inconsistent with most of DBusString in that
558  * it allows a start,len range that extends past the string end.
559  *
560  * @todo change spec to disallow more things, such as spaces in the
561  * path name
562  *
563  * @param str the string
564  * @param start first byte index to check
565  * @param len number of bytes to check
566  * @returns #TRUE if the byte range exists and is a valid name
567  */
568 dbus_bool_t
569 _dbus_validate_path (const DBusString  *str,
570                      int                start,
571                      int                len)
572 {
573   const unsigned char *s;
574   const unsigned char *end;
575   const unsigned char *last_slash;
576
577   _dbus_assert (start >= 0);
578   _dbus_assert (len >= 0);
579   _dbus_assert (start <= _dbus_string_get_length (str));
580   
581   if (len > _dbus_string_get_length (str) - start)
582     return FALSE;
583
584   if (len == 0)
585     return FALSE;
586
587   s = _dbus_string_get_const_data (str) + start;
588   end = s + len;
589
590   if (*s != '/')
591     return FALSE;
592   last_slash = s;
593   ++s;
594
595   while (s != end)
596     {
597       if (*s == '/')
598         {
599           if ((s - last_slash) < 2)
600             return FALSE; /* no empty path components allowed */
601
602           last_slash = s;
603         }
604       else
605         {
606           if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
607             return FALSE;
608         }
609
610       ++s;
611     }
612
613   if ((end - last_slash) < 2 &&
614       len > 1)
615     return FALSE; /* trailing slash not allowed unless the string is "/" */
616
617   return TRUE;
618 }
619
620 /**
621  * Checks that the given range of the string is a valid interface name
622  * in the D-BUS protocol. This includes a length restriction and an
623  * ASCII subset, see the specification.
624  *
625  * @todo this is inconsistent with most of DBusString in that
626  * it allows a start,len range that extends past the string end.
627  *
628  * @param str the string
629  * @param start first byte index to check
630  * @param len number of bytes to check
631  * @returns #TRUE if the byte range exists and is a valid name
632  */
633 dbus_bool_t
634 _dbus_validate_interface (const DBusString  *str,
635                           int                start,
636                           int                len)
637 {
638   const unsigned char *s;
639   const unsigned char *end;
640   const unsigned char *iface;
641   const unsigned char *last_dot;
642
643   _dbus_assert (start >= 0);
644   _dbus_assert (len >= 0);
645   _dbus_assert (start <= _dbus_string_get_length (str));
646
647   if (len > _dbus_string_get_length (str) - start)
648     return FALSE;
649
650   if (len > DBUS_MAXIMUM_NAME_LENGTH)
651     return FALSE;
652
653   if (len == 0)
654     return FALSE;
655
656   last_dot = NULL;
657   iface = _dbus_string_get_const_data (str) + start;
658   end = iface + len;
659   s = iface;
660
661   /* check special cases of first char so it doesn't have to be done
662    * in the loop. Note we know len > 0
663    */
664   if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */
665     return FALSE;
666   else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
667     return FALSE;
668   else
669     ++s;
670
671   while (s != end)
672     {
673       if (*s == '.')
674         {
675           if (_DBUS_UNLIKELY ((s + 1) == end))
676             return FALSE;
677           else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*(s + 1))))
678             return FALSE;
679           last_dot = s;
680           ++s; /* we just validated the next char, so skip two */
681         }
682       else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
683         {
684           return FALSE;
685         }
686
687       ++s;
688     }
689
690   if (_DBUS_UNLIKELY (last_dot == NULL))
691     return FALSE;
692
693   return TRUE;
694 }
695
696 /**
697  * Checks that the given range of the string is a valid member name
698  * in the D-BUS protocol. This includes a length restriction, etc.,
699  * see the specification.
700  *
701  * @todo this is inconsistent with most of DBusString in that
702  * it allows a start,len range that extends past the string end.
703  *
704  * @param str the string
705  * @param start first byte index to check
706  * @param len number of bytes to check
707  * @returns #TRUE if the byte range exists and is a valid name
708  */
709 dbus_bool_t
710 _dbus_validate_member (const DBusString  *str,
711                        int                start,
712                        int                len)
713 {
714   const unsigned char *s;
715   const unsigned char *end;
716   const unsigned char *member;
717
718   _dbus_assert (start >= 0);
719   _dbus_assert (len >= 0);
720   _dbus_assert (start <= _dbus_string_get_length (str));
721
722   if (len > _dbus_string_get_length (str) - start)
723     return FALSE;
724
725   if (len > DBUS_MAXIMUM_NAME_LENGTH)
726     return FALSE;
727
728   if (len == 0)
729     return FALSE;
730
731   member = _dbus_string_get_const_data (str) + start;
732   end = member + len;
733   s = member;
734
735   /* check special cases of first char so it doesn't have to be done
736    * in the loop. Note we know len > 0
737    */
738
739   if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
740     return FALSE;
741   else
742     ++s;
743
744   while (s != end)
745     {
746       if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
747         {
748           return FALSE;
749         }
750
751       ++s;
752     }
753
754   return TRUE;
755 }
756
757 /**
758  * Checks that the given range of the string is a valid error name
759  * in the D-BUS protocol. This includes a length restriction, etc.,
760  * see the specification.
761  *
762  * @todo this is inconsistent with most of DBusString in that
763  * it allows a start,len range that extends past the string end.
764  *
765  * @param str the string
766  * @param start first byte index to check
767  * @param len number of bytes to check
768  * @returns #TRUE if the byte range exists and is a valid name
769  */
770 dbus_bool_t
771 _dbus_validate_error_name (const DBusString  *str,
772                            int                start,
773                            int                len)
774 {
775   /* Same restrictions as interface name at the moment */
776   return _dbus_validate_interface (str, start, len);
777 }
778
779 /* This assumes the first char exists and is ':' */
780 static dbus_bool_t
781 _dbus_validate_unique_name (const DBusString  *str,
782                             int                start,
783                             int                len)
784 {
785   const unsigned char *s;
786   const unsigned char *end;
787   const unsigned char *name;
788
789   _dbus_assert (start >= 0);
790   _dbus_assert (len >= 0);
791   _dbus_assert (start <= _dbus_string_get_length (str));
792
793   if (len > _dbus_string_get_length (str) - start)
794     return FALSE;
795
796   if (len > DBUS_MAXIMUM_NAME_LENGTH)
797     return FALSE;
798
799   _dbus_assert (len > 0);
800
801   name = _dbus_string_get_const_data (str) + start;
802   end = name + len;
803   _dbus_assert (*name == ':');
804   s = name + 1;
805
806   while (s != end)
807     {
808       if (*s == '.')
809         {
810           if (_DBUS_UNLIKELY ((s + 1) == end))
811             return FALSE;
812           if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*(s + 1))))
813             return FALSE;
814           ++s; /* we just validated the next char, so skip two */
815         }
816       else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
817         {
818           return FALSE;
819         }
820
821       ++s;
822     }
823
824   return TRUE;
825 }
826
827 /**
828  * Checks that the given range of the string is a valid bus name in
829  * the D-BUS protocol. This includes a length restriction, etc., see
830  * the specification.
831  *
832  * @todo this is inconsistent with most of DBusString in that
833  * it allows a start,len range that extends past the string end.
834  *
835  * @param str the string
836  * @param start first byte index to check
837  * @param len number of bytes to check
838  * @returns #TRUE if the byte range exists and is a valid name
839  */
840 dbus_bool_t
841 _dbus_validate_bus_name (const DBusString  *str,
842                          int                start,
843                          int                len)
844 {
845   if (_DBUS_UNLIKELY (len == 0))
846     return FALSE;
847   if (_dbus_string_get_byte (str, start) == ':')
848     return _dbus_validate_unique_name (str, start, len);
849   else
850     return _dbus_validate_interface (str, start, len);
851 }
852
853 /**
854  * Checks that the given range of the string is a valid message type
855  * signature in the D-BUS protocol.
856  *
857  * @todo this is inconsistent with most of DBusString in that
858  * it allows a start,len range that extends past the string end.
859  *
860  * @param str the string
861  * @param start first byte index to check
862  * @param len number of bytes to check
863  * @returns #TRUE if the byte range exists and is a valid signature
864  */
865 dbus_bool_t
866 _dbus_validate_signature (const DBusString  *str,
867                           int                start,
868                           int                len)
869 {
870   _dbus_assert (start >= 0);
871   _dbus_assert (start <= _dbus_string_get_length (str));
872   _dbus_assert (len >= 0);
873
874   if (len > _dbus_string_get_length (str) - start)
875     return FALSE;
876
877   return _dbus_validate_signature_with_reason (str, start, len) == DBUS_VALID;
878 }
879
880 /** define _dbus_check_is_valid_path() */
881 DEFINE_DBUS_NAME_CHECK(path);
882 /** define _dbus_check_is_valid_interface() */
883 DEFINE_DBUS_NAME_CHECK(interface);
884 /** define _dbus_check_is_valid_member() */
885 DEFINE_DBUS_NAME_CHECK(member);
886 /** define _dbus_check_is_valid_error_name() */
887 DEFINE_DBUS_NAME_CHECK(error_name);
888 /** define _dbus_check_is_valid_bus_name() */
889 DEFINE_DBUS_NAME_CHECK(bus_name);
890 /** define _dbus_check_is_valid_signature() */
891 DEFINE_DBUS_NAME_CHECK(signature);
892
893 /** @} */
894
895 /* tests in dbus-marshal-validate-util.c */