1 /*
2 
3                           Firewall Builder
4 
5                  Copyright (C) 2001 NetCitadel, LLC
6 
7   Author:  Vadim Zaliva lord@crocodile.org
8 
9   $Id$
10 
11   This program is free software which we release under the GNU General Public
12   License. You may redistribute and/or modify this program under the terms
13   of that license as published by the Free Software Foundation; either
14   version 2 of the License, or (at your option) any later version.
15 
16   This program is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20 
21   To get a copy of the GNU General Public License, write to the Free Software
22   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 
24 */
25 
26 
27 #ifndef __FWOBJECTDATABASE_HH_FLAG__
28 #define __FWOBJECTDATABASE_HH_FLAG__
29 
30 #include "fwbuilder/FWObject.h"
31 #include "fwbuilder/FWException.h"
32 #include "fwbuilder/ThreadTools.h"
33 #include "fwbuilder/XMLTools.h"
34 
35 #ifdef _WIN32
36 #  include <sys/timeb.h>
37 #  include <process.h>
38 #else
39 #  include <sys/types.h>
40 #  include <unistd.h>
41 #endif
42 
43 #include <time.h>   // for time_t
44 
45 #define DECLARE_CREATE_OBJ_METHOD(classname) \
46     FWObject* create_##classname(int id=-1);
47 
48 #define DECLARE_CREATE_OBJ_CLASS_METHOD(classname) \
49     classname * create##classname(int id=-1);
50 
51 
52 namespace libfwbuilder
53 {
54     class Group;
55 
56     // forward declarations for specialized create() methods
57     class AddressRange;
58     class AddressTable;
59     class AttachedNetworks;
60     class Cluster;
61     class StateSyncClusterGroup;
62     class FailoverClusterGroup;
63     class ClusterGroupOptions;
64     class CustomService;
65     class DNSName;
66     class DynamicGroup;
67     class FWBDManagement;
68     class FWIntervalReference;
69     class FWObjectReference;
70     class FWServiceReference;
71     class Firewall;
72     class FirewallOptions;
73     class Host;
74     class HostOptions;
75     class ICMP6Service;
76     class ICMPService;
77     class IPService;
78     class IPv4;
79     class IPv6;
80     class Interface;
81     class InterfaceOptions;
82     class Interval;
83     class IntervalGroup;
84     class Library;
85     class Management;
86     class NAT;
87     class NATRule;
88     class NATRuleOptions;
89     class Network;
90     class NetworkIPv6;
91     class ObjectGroup;
92     class Policy;
93     class PolicyInstallScript;
94     class PolicyRule;
95     class PolicyRuleOptions;
96     class Routing;
97     class RoutingRule;
98     class RoutingRuleOptions;
99     class RuleElementDst;
100     class RuleElementInterval;
101     class RuleElementItf;
102     class RuleElementItfInb;
103     class RuleElementItfOutb;
104     class RuleElementODst;
105     class RuleElementOSrc;
106     class RuleElementOSrv;
107     class RuleElementRDst;
108     class RuleElementRGtw;
109     class RuleElementRItf;
110     class RuleElementSrc;
111     class RuleElementSrv;
112     class RuleElementTDst;
113     class RuleElementTSrc;
114     class RuleElementTSrv;
115     class RuleSetOptions;
116     class SNMPManagement;
117     class ServiceGroup;
118     class TCPService;
119     class TagService;
120     class UDPService;
121     class UserService;
122     class physAddress;
123 
124 
125 
126     DECLARE_CREATE_OBJ_METHOD(AddressRange);
127     DECLARE_CREATE_OBJ_METHOD(AddressTable);
128     DECLARE_CREATE_OBJ_METHOD(AttachedNetworks);
129     DECLARE_CREATE_OBJ_METHOD(Cluster);
130     DECLARE_CREATE_OBJ_METHOD(StateSyncClusterGroup);
131     DECLARE_CREATE_OBJ_METHOD(FailoverClusterGroup);
132     DECLARE_CREATE_OBJ_METHOD(ClusterGroupOptions);
133     DECLARE_CREATE_OBJ_METHOD(CustomService);
134     DECLARE_CREATE_OBJ_METHOD(DNSName);
135     DECLARE_CREATE_OBJ_METHOD(DynamicGroup);
136     DECLARE_CREATE_OBJ_METHOD(FWBDManagement);
137     DECLARE_CREATE_OBJ_METHOD(FWIntervalReference);
138     DECLARE_CREATE_OBJ_METHOD(FWObjectReference);
139     DECLARE_CREATE_OBJ_METHOD(FWServiceReference);
140     DECLARE_CREATE_OBJ_METHOD(Firewall);
141     DECLARE_CREATE_OBJ_METHOD(FirewallOptions);
142     DECLARE_CREATE_OBJ_METHOD(Host);
143     DECLARE_CREATE_OBJ_METHOD(HostOptions);
144     DECLARE_CREATE_OBJ_METHOD(ICMP6Service);
145     DECLARE_CREATE_OBJ_METHOD(ICMPService);
146     DECLARE_CREATE_OBJ_METHOD(IPService);
147     DECLARE_CREATE_OBJ_METHOD(IPv4);
148     DECLARE_CREATE_OBJ_METHOD(IPv6);
149     DECLARE_CREATE_OBJ_METHOD(Interface);
150     DECLARE_CREATE_OBJ_METHOD(InterfaceOptions);
151     DECLARE_CREATE_OBJ_METHOD(Interval);
152     DECLARE_CREATE_OBJ_METHOD(IntervalGroup);
153     DECLARE_CREATE_OBJ_METHOD(Library);
154     DECLARE_CREATE_OBJ_METHOD(Management);
155     DECLARE_CREATE_OBJ_METHOD(NAT);
156     DECLARE_CREATE_OBJ_METHOD(NATRule);
157     DECLARE_CREATE_OBJ_METHOD(NATRuleOptions);
158     DECLARE_CREATE_OBJ_METHOD(Network);
159     DECLARE_CREATE_OBJ_METHOD(NetworkIPv6);
160     DECLARE_CREATE_OBJ_METHOD(ObjectGroup);
161     DECLARE_CREATE_OBJ_METHOD(Policy);
162     DECLARE_CREATE_OBJ_METHOD(PolicyInstallScript);
163     DECLARE_CREATE_OBJ_METHOD(PolicyRule);
164     DECLARE_CREATE_OBJ_METHOD(PolicyRuleOptions);
165     DECLARE_CREATE_OBJ_METHOD(Routing);
166     DECLARE_CREATE_OBJ_METHOD(RoutingRule);
167     DECLARE_CREATE_OBJ_METHOD(RoutingRuleOptions);
168     DECLARE_CREATE_OBJ_METHOD(RuleElementDst);
169     DECLARE_CREATE_OBJ_METHOD(RuleElementInterval);
170     DECLARE_CREATE_OBJ_METHOD(RuleElementItf);
171     DECLARE_CREATE_OBJ_METHOD(RuleElementItfInb);
172     DECLARE_CREATE_OBJ_METHOD(RuleElementItfOutb);
173     DECLARE_CREATE_OBJ_METHOD(RuleElementODst);
174     DECLARE_CREATE_OBJ_METHOD(RuleElementOSrc);
175     DECLARE_CREATE_OBJ_METHOD(RuleElementOSrv);
176     DECLARE_CREATE_OBJ_METHOD(RuleElementRDst);
177     DECLARE_CREATE_OBJ_METHOD(RuleElementRGtw);
178     DECLARE_CREATE_OBJ_METHOD(RuleElementRItf);
179     DECLARE_CREATE_OBJ_METHOD(RuleElementSrc);
180     DECLARE_CREATE_OBJ_METHOD(RuleElementSrv);
181     DECLARE_CREATE_OBJ_METHOD(RuleElementTDst);
182     DECLARE_CREATE_OBJ_METHOD(RuleElementTSrc);
183     DECLARE_CREATE_OBJ_METHOD(RuleElementTSrv);
184     DECLARE_CREATE_OBJ_METHOD(RuleSetOptions);
185     DECLARE_CREATE_OBJ_METHOD(SNMPManagement);
186     DECLARE_CREATE_OBJ_METHOD(ServiceGroup);
187     DECLARE_CREATE_OBJ_METHOD(TCPService);
188     DECLARE_CREATE_OBJ_METHOD(TagService);
189     DECLARE_CREATE_OBJ_METHOD(UDPService);
190     DECLARE_CREATE_OBJ_METHOD(UserService);
191     DECLARE_CREATE_OBJ_METHOD(physAddress);
192     DECLARE_CREATE_OBJ_METHOD(Group);
193 
194 
195     class IDcounter {
196 
197 protected:
198         long cntr;
199 
200 public:
201         IDcounter();
get()202         long get() { ++cntr; return cntr; }
203     };
204 
205     class FWObjectDatabase;
206     typedef FWObject*(*create_function_ptr)(int);
207 
208     /**
209      * Database of objects.
210      */
211     class FWObjectDatabase : public FWObject
212     {
213 
214 private:
215         void _clearReferenceCounters(FWObject *o);
216         void _fixReferenceCounters(FWObject *o);
217         bool _isInIgnoreList(FWObject *o);
218 
219         /* bool _findWhereUsed( */
220         /*         libfwbuilder::FWObject *o, */
221         /*         libfwbuilder::FWObject *p, */
222         /*         std::set<libfwbuilder::FWObject *> &resset); */
223 
224         bool _findWhereObjectIsUsed(libfwbuilder::FWObject *o,
225                                     libfwbuilder::FWObject *p,
226                                     std::set<libfwbuilder::FWObject *> &resset,
227                                     int search_id);
228 
229         void _findObjectsInGroup(
230             libfwbuilder::Group *g,
231             std::set<libfwbuilder::FWObject *> &res);
232         Firewall* _findFirewallByNameRecursive(
233             FWObject* db, const std::string &name) throw(FWException);
234         FWObject* _recursively_copy_subtree(FWObject *target,
235                                             FWObject *source,
236                                             std::map<int,int> &id_map,
237                                             const std::string &dedup_attribute);
238         void _copy_foreign_obj_aux(FWObject *target, FWObject *source,
239                                    std::map<int,int> &id_map,
240                                    const std::string &dedup_attribute);
241 
242         void _setPredictableStrIdsRecursively(FWObject *obj);
243         void _updateNonStandardObjectReferencesRecursively(FWObject *obj);
244 
245 protected:
246 
247         static const std::string DTD_FILE_NAME ;
248 
249         time_t lastModified;
250         int index_hits;
251         int index_misses;
252         std::string data_file;
253         std::map<int, FWObject*> obj_index;
254         int searchId;
255         int predictable_id_tracker;
256         bool ignore_read_only;
257 
258         void init_create_methods_table();
259         void init_id_dict();
260 
261 public:
262 
263         DECLARE_FWOBJECT_SUBTYPE(FWObjectDatabase);
264 
265         DECLARE_DISPATCH_METHODS(FWObjectDatabase);
266 
267         enum {ROOT_ID = 0,
268               ANY_ADDRESS_ID = 1,
269               ANY_SERVICE_ID = 2,
270               ANY_INTERVAL_ID = 3,
271               STANDARD_LIB_ID = 4,
272               USER_LIB_ID = 5,
273               TEMPLATE_LIB_ID = 6,
274               DELETED_OBJECTS_ID = 7,
275               DUMMY_ADDRESS_ID = 8,
276               DUMMY_SERVICE_ID = 9,
277               DUMMY_INTERFACE_ID = 10
278         } standard_ids;
279 
280         static void registerObjectType(const std::string &type_name,
281                                        create_function_ptr create_function);
282 
283         /**
284          * this constructor initializes singleton db
285          */
286         FWObjectDatabase();
287         /**
288          * this constructor makes a copy of entire tree and does not
289          * intitialize db
290          */
291         FWObjectDatabase(FWObjectDatabase& d);
292 
293         virtual ~FWObjectDatabase();
294 
295         // --- methods dealing with object index
296 
297         void addToIndexRecursive(FWObject *o);
298 
299         /**
300          * add an object to the index
301          */
302         void addToIndex(FWObject* obj);
303 
304         /**
305          * remove an object from the index
306          */
307         void removeFromIndex(int id);
308 
309         /**
310          * check if an object is present in the index using its ID
311          */
312         FWObject* checkIndex(int id);
313 
314         /**
315          * find an object in the index using its ID
316          */
317         FWObject* findInIndex(int id);
318 
319         /**
320          * build index
321          */
322         void buildIndex();
323 
324         /**
325          * clear the index
326          */
327         void clearIndex();
328 
329         /**
330          * this is just like buildIndex, except it also fixes reference
331          * counters in objects. Call this method after loading database
332          * from XML file. This method uses private _fixReferenceCounters
333          */
334         void reIndex();
335 
336         /**
337          * return index usage statistics
338          */
339         void getIndexStats(int &index_size, int &hit_counter, int &miss_counter);
340 
341         /**
342          * this function is intended for debugging.
343          */
344         void validateIndex();
345 
346         /**
347          * Some operations, such as object tree merging, should ignore
348          * read-only flag on individual objects.
349          */
getIgnoreReadOnlyFlag()350         bool getIgnoreReadOnlyFlag() { return ignore_read_only; }
setIgnoreReadOnlyFlag(bool f)351         void setIgnoreReadOnlyFlag(bool f) { ignore_read_only = f; }
352 
353         // --- XML import/export ---
354 
355         virtual void fromXML(xmlNodePtr xml_parent_node) throw(FWException);
356         virtual xmlNodePtr toXML(xmlNodePtr parent) throw(FWException);
357 
getTimeLastModified()358         time_t getTimeLastModified() { return lastModified; }
resetTimeLastModified(time_t t)359         void resetTimeLastModified(time_t t) { lastModified=t; }
360 
361         // --- Load/Save ---
362 
363         virtual void saveFile(const std::string &filename) throw(FWException);
364         virtual void saveToBuffer(xmlChar **buffer,int *size) throw(FWException);
365         virtual void load( const std::string &filename,
366                            XMLTools::UpgradePredicate *upgrade,
367                            const std::string &template_dir) throw(FWException);
368         virtual void setDirty(bool f);
369 
370         Firewall* findFirewallByName(const std::string &name) throw(FWException);
371 
372         FWObjectDatabase* exportSubtree( FWObject *lib );
373         FWObjectDatabase* exportSubtree( const std::list<FWObject*> &libs );
374 
375 
376         /* void findWhereUsed( */
377         /*         libfwbuilder::FWObject *o, */
378         /*         libfwbuilder::FWObject *p, */
379         /*         std::set<libfwbuilder::FWObject *> &resset); */
380 
381         /**
382          * Find reference to object <o> in the subtree rooted at <p>. Do
383          * not search for indirect usage, i.e. when an object has a
384          * reference to a group that in turn has reference to <o>. Search
385          * also includes references to objects used in rule actions Tag
386          * and Branch.
387          */
388         void findWhereObjectIsUsed(
389             libfwbuilder::FWObject *o,
390             libfwbuilder::FWObject *p,
391             std::set<libfwbuilder::FWObject *> &resset);
392 
393         /**
394          * find all objects used by the group 'gr'. Resolve references
395          * recursively (that is, if a group member is another group, this
396          * method descends into it and scans all objects that group uses)
397          */
398         void findObjectsInGroup(
399             libfwbuilder::Group *g,
400             std::set<libfwbuilder::FWObject *> &resset);
401 
402         /**
403          * We ignore read-only flag on individual objects when whole object
404          * tree is duplicated
405          */
406         virtual FWObject& duplicate(const FWObject *obj,
407                                     bool preserve_id = true) throw(FWException);
408 
409 
410         void recursivelyRemoveObjFromTree(FWObject* obj, bool remove_ref=false);
411 
412         /**
413          * Copy <source> object and all its children, recursively, into <this>
414          * object tree starting from <target>. <target> is a parent of the copy
415          * of <source> that will be created.
416          * Store ID mapping in <id_map> (as a dictionary old_id -> new_id)
417          */
418         FWObject* recursivelyCopySubtree(FWObject *target,
419                                          FWObject *source,
420                                          std::map<int,int> &id_map);
421 
422         /**
423          * Create groups to reproduce path inside given library. If groups
424          * with required names exist, do nothing. Return pointer to the
425          * last object created to copy the path. Do not copy <source> object.
426          * This means returned object can be a parent for the copy of <source>.
427          */
428         FWObject* reproduceRelativePath(FWObject *lib, const FWObject *source);
429 
430         /**
431          * fix references in children of obj according to the map_ids which
432          * maps old IDs to the new ones. Return the number of fixed references.
433          */
434         int fixReferences(FWObject *obj, const std::map<int,int> &map_ids);
435 
436         /**
437          * this predicate is used to hand control over to user in case
438          * when a conflict is detected while merging trees. By default the
439          * old object is overwritten with new one.
440          */
441         class ConflictResolutionPredicate
442         {
443     public:
~ConflictResolutionPredicate()444             virtual ~ConflictResolutionPredicate() {}
askUser(FWObject *,FWObject *)445             virtual bool askUser(FWObject*,FWObject*)
446             {
447                 return true;
448             }
449         };
450 
451         void merge(FWObjectDatabase *ndb, ConflictResolutionPredicate *mp=NULL);
452         void findDuplicateIds(FWObjectDatabase *ndb, std::set<int> &dupids);
453 
454         void setFileName(const std::string &filename);
455         const std::string& getFileName ();
456         const std::string  getFileDir ();
457 
458         static int generateUniqueId();
459         static int registerStringId(const std::string &s_id);
460         static int getIntId(const std::string &s_id);
461         static std::string getStringId(int i_id);
462 
463         /**
464          * generate predictable ID based on given prefix by adding sequential
465          * suffix to it.
466          */
467         std::string getPredictableId(const std::string &prefix);
468 
469         /**
470          * This method replaces random string object ids with
471          * predictable ones. This does not change their int IDs, only
472          * string IDs that appear in the XML file when objects are
473          * saved change.
474          *
475          * Used in unit testing to create .fwb files that can be
476          * compared.
477          */
478         virtual void setPredictableIds();
479 
480         /**
481          * This is the main "Create" method:
482          * it creates instance of FWObject of given type
483          *
484          * if parameter 'create_with_root' is true, this method will create
485          * objects using constructor that uses pointer to this as a parameter,
486          * otherwise empty constructor is used
487          */
488         FWObject *create(const std::string &type, int id=-1, bool init=true);
489 
490         /**
491          * Creates instance of FWObject using its XML representation
492          */
493         virtual FWObject *createFromXML(xmlNodePtr data);
494 
495         /**
496          * Specialized createClass() methods: class name is part of the method
497          * name, e.g. createLibrary(), also these return a pointer to the
498          * corresponding class. Note that each macro declares two methods:
499          * Class* createClass(int,bool) and FWObject* createFWObjectClass(int,bool)
500          */
501 
502     DECLARE_CREATE_OBJ_CLASS_METHOD(AddressRange);
503     DECLARE_CREATE_OBJ_CLASS_METHOD(AddressTable);
504     DECLARE_CREATE_OBJ_CLASS_METHOD(AttachedNetworks);
505     DECLARE_CREATE_OBJ_CLASS_METHOD(Cluster);
506     DECLARE_CREATE_OBJ_CLASS_METHOD(StateSyncClusterGroup);
507     DECLARE_CREATE_OBJ_CLASS_METHOD(FailoverClusterGroup);
508     DECLARE_CREATE_OBJ_CLASS_METHOD(ClusterGroupOptions);
509     DECLARE_CREATE_OBJ_CLASS_METHOD(CustomService);
510     DECLARE_CREATE_OBJ_CLASS_METHOD(DNSName);
511     DECLARE_CREATE_OBJ_CLASS_METHOD(DynamicGroup);
512     DECLARE_CREATE_OBJ_CLASS_METHOD(FWBDManagement);
513     DECLARE_CREATE_OBJ_CLASS_METHOD(FWIntervalReference);
514     DECLARE_CREATE_OBJ_CLASS_METHOD(FWObjectReference);
515     DECLARE_CREATE_OBJ_CLASS_METHOD(FWServiceReference);
516     DECLARE_CREATE_OBJ_CLASS_METHOD(Firewall);
517     DECLARE_CREATE_OBJ_CLASS_METHOD(FirewallOptions);
518     DECLARE_CREATE_OBJ_CLASS_METHOD(Host);
519     DECLARE_CREATE_OBJ_CLASS_METHOD(HostOptions);
520     DECLARE_CREATE_OBJ_CLASS_METHOD(ICMP6Service);
521     DECLARE_CREATE_OBJ_CLASS_METHOD(ICMPService);
522     DECLARE_CREATE_OBJ_CLASS_METHOD(IPService);
523     DECLARE_CREATE_OBJ_CLASS_METHOD(IPv4);
524     DECLARE_CREATE_OBJ_CLASS_METHOD(IPv6);
525     DECLARE_CREATE_OBJ_CLASS_METHOD(Interface);
526     DECLARE_CREATE_OBJ_CLASS_METHOD(InterfaceOptions);
527     DECLARE_CREATE_OBJ_CLASS_METHOD(Interval);
528     DECLARE_CREATE_OBJ_CLASS_METHOD(IntervalGroup);
529     DECLARE_CREATE_OBJ_CLASS_METHOD(Library);
530     DECLARE_CREATE_OBJ_CLASS_METHOD(Management);
531     DECLARE_CREATE_OBJ_CLASS_METHOD(NAT);
532     DECLARE_CREATE_OBJ_CLASS_METHOD(NATRule);
533     DECLARE_CREATE_OBJ_CLASS_METHOD(NATRuleOptions);
534     DECLARE_CREATE_OBJ_CLASS_METHOD(Network);
535     DECLARE_CREATE_OBJ_CLASS_METHOD(NetworkIPv6);
536     DECLARE_CREATE_OBJ_CLASS_METHOD(ObjectGroup);
537     DECLARE_CREATE_OBJ_CLASS_METHOD(Policy);
538     DECLARE_CREATE_OBJ_CLASS_METHOD(PolicyInstallScript);
539     DECLARE_CREATE_OBJ_CLASS_METHOD(PolicyRule);
540     DECLARE_CREATE_OBJ_CLASS_METHOD(PolicyRuleOptions);
541     DECLARE_CREATE_OBJ_CLASS_METHOD(Routing);
542     DECLARE_CREATE_OBJ_CLASS_METHOD(RoutingRule);
543     DECLARE_CREATE_OBJ_CLASS_METHOD(RoutingRuleOptions);
544     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementDst);
545     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementInterval);
546     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementItf);
547     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementItfInb);
548     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementItfOutb);
549     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementODst);
550     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementOSrc);
551     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementOSrv);
552     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementRDst);
553     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementRGtw);
554     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementRItf);
555     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementSrc);
556     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementSrv);
557     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementTDst);
558     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementTSrc);
559     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleElementTSrv);
560     DECLARE_CREATE_OBJ_CLASS_METHOD(RuleSetOptions);
561     DECLARE_CREATE_OBJ_CLASS_METHOD(SNMPManagement);
562     DECLARE_CREATE_OBJ_CLASS_METHOD(ServiceGroup);
563     DECLARE_CREATE_OBJ_CLASS_METHOD(TCPService);
564     DECLARE_CREATE_OBJ_CLASS_METHOD(TagService);
565     DECLARE_CREATE_OBJ_CLASS_METHOD(UDPService);
566     DECLARE_CREATE_OBJ_CLASS_METHOD(UserService);
567     DECLARE_CREATE_OBJ_CLASS_METHOD(physAddress);
568     DECLARE_CREATE_OBJ_CLASS_METHOD(Group);
569 
570 
571     };
572 
573 }
574 
575 #endif
576 
577