Ganymede Schema Definition in XML |
The <ganyschema> element defines the structure of the Ganymede database, what types of objects are defined, what fields they have, what kind of data those fields can contained, and what everything is called.
The <ganyschema> element is optional. If you
run 'xmlclient -dumpschema
' or 'xmlclient -dump
', you will get
an XML file that includes the <ganyschema> element.
If you run xmlclient on an XML file that includes a <ganyschema>
element, xmlclient will attempt to edit the server's schema to
bring it into alignment with that described in the <ganyschema>
element.
The <ganyschema> element contains two other elements, <namespaces> and <object_type_definitions>.
<ganyschema> <namespaces> -- Optional Namespace Definitions -- </namespaces> <object_type_definitions> -- Object And Field Definitions -- </object_type_definitions> </ganyschema>
<namespaces> |
The <namespaces> element contains definition elements for all unique namespace structures in the server. A namespace is essentially a unique value index that the server uses to assure that, across all fields in the database connected to the namespace, no value is repeated. Namespaces are used to keep user, group, and system names unique, among other things.
Here is an example <namespaces> element that would be contained at the start of a <ganyschema> element:
<namespaces> <namespace name="username"/> <namespace name="groupname"/> <namespace name="IPspace"/> <namespace name="UserCategory" case-sensitive="true"/> <namespace name="systemtype" case-sensitive="true"/> </namespaces>
In this example, the username, groupname, and IPspace namespaces consider two strings to be equivalent for namespace conflict considerations even if two instances of the string have different capitalization. The UserCategory and systemtype name spaces will not consider two strings to be in conflict if they have different capitalizations.
Namespaces are only significant when they are attached to fields in the <object_type_definitions> section, as we will see shortly.
<object_type_definitions> |
In the Ganymede server, all data stored is stored in the form of fields, which are aggregated in objects. Each object stored in the Ganymede server is of a certain type, such as a user, group, system, network, or whatever else has been defined in the server's schema. The objects, in turn, may be grouped into categories. Categories are a way of grouping similar kinds of objects together so that they may be viewed or ignored in the client's tree view.
The <object_type_definitions> element under the <ganyschema> element contains the actual schema definition information in terms of categories, objects, and fields. The corresponding elements for these are the <category>, <objectdef>, and <fielddef> elements.
Here is an example:
<object_type_definitions> <category name="Categories"> <category name="Admin-Level Objects"> <category name="Events"> <objectdef name="System_Events" id="4"> <label fieldid="100"/> <classdef name="arlut.csd.ganymede.eventCustom"/> <tab name="General"/> <fielddef name="Event_Token" id="100"> <comment>Single-word token for this event class</comment> <typedef type="string"> <maxlength val="32"/> <badchars val=" |"/> <namespace val="eventtoken"/> </typedef> </fielddef> <fielddef name="Event_Mail" id="103"> <comment>If true, events of this type should be mailed</comment> <typedef type="boolean"/> </fielddef> <fielddef name="Mail_List" id="107"> <typedef type="string"> <vector/> </typedef> </fielddef> </tab> </objectdef> </category> </category> </category> </object_type_definitions>
This example is of a small portion of a Ganymede server's schema definition. This fragment shows an object type called 'System Events' which holds a single tab, 'General, containing three fields; a scalar string field called 'Event Token' which is connected to the 'eventtoken' namespace, a boolean checkbox field called 'Event Mail', and a vector string field called 'Mail List'.
The 'System Events' object is contained within an 'Events' category, which is contained in turn within a 'Admin-Level Objects' category. The 'Categories' category is itself simply a container for the other categories.. it is the category root node. All <object_type_definitions> elements in Ganymede XML schema definition sections should contain a top-level 'Categories' category, even if you don't want any categorical organization of object types in the client. Note that all <category> elements that are opened are properly closed before the close of the <object_type_definitions> element.
<objectdef> |
The objectdef element is used to define object types in the Ganymede server. Each object type has a name and a numeric id, which are defined in an open objectdef tag via the 'name' and 'id' attributes. Both of these values must be unique within the <ganyschema> section. The value of the 'id' attribute must be an integer number, and the value of the 'name' attribute must be a string which contains only the letters a-z, in upper or lower case, numbers, a period, a dash, or a space.
Example:
<objectdef name="User" id="3">
The objectdef element must contain the mandatory <label> element to control what namespace-controlled field will act as the object's label. There can also be an optional <classdef> element to define the Java plugin class used to control operations on the object, along with an optional <embedded> element to designate objects that are to be contained in other objects. After these two or three top-level elements, there will be a series of tab elements, which in turn will contain fielddef elements to define the tabs and fields in this object type.
The mandatory label element has a fieldid attribute which gives the numeric field id of the field within the object which is to serve as the label field. Objects must have one and only one designated label field and it must refer to a namespace-controlled String, IP, or Numeric field defined within the <objectdef> element. Float, Password, Permission Matrix, Object Reference, Field Option, and Boolean fields may not be specified as label fields. The label element must be empty.
Example:
<label fieldid="100"/>
The classdef element, if present, specifies the fully
qualified class name of a Java class to be loaded by the server to
manage server operations on objects of this type. As of version
2.0 of Ganymede, the classdef element has two
attributes. The name attribute whose value is the fully
qualified name of the Java class to be used. The
optionString attribute is provided to support the use of
Jython for writing DBEditObject subclass plugins. If present, the
optionString attribute should contain a URL where the
Jython program text for the plugin can be found. Note that the
optionString will be ignored unless the Java class named in
the classdef attribute knows to use it. In the case of the
Jython support, you'd need to set classdef to
arlut.csd.ganymede.server.JythonEditObjectFactory
.
See the DBEditObject subclassing guide for details on the use of custom classes in the Ganymede server. The classdef element must be empty. That is, it must not contain any other elements.
Example:
<classdef name="arlut.csd.ganymede.gasharl.userCustom"/>
Second Example:
<classdef name="arlut.csd.ganymede.server.JythonEditObjectFactory" optionString="file:///server/ganymede/jython/classplugin.py"/>
The optional embedded element, if present, indicates that the object is not a top-level object which will be shown in the client's object tree and which will have its ownership and permissions tracked independently, but rather is an embedded object which will be encapsulated in another object of a defined type. The embedded element must be empty and it takes no attributes.
Example:
<embedded/>
Once these top-level elements are out of the way, we get down to the meat of an object definition element.. the fields, and the tabs they are contained in. The objectdef element contains a series of one or more tab elements. These tab elements, in turn, contain fielddef elements, one for each field defined in this object type. These fielddef elements are listed in the order they should appear in the client. The first fielddef element in an tab element will appear at the top of the object editing window in the Ganymede client, with subsequent fielddef's in the same tab in order below the first.
<tab> |
The tab element is a container for fielddef elements. It has a single attribute, name, which contains the name of the tab.
If you define multiple named tab elements within an object definition, the Ganymede client will display the fields in each tab element in a separate graphical tab in the object viewing and editing window. This can be useful when you start getting too large a number of fields for a user to be able to conveniently deal with in a single scrolling panel.
In all other contents (logging, email, the contents of the XML <ganydata> element, and so forth), the tab information is irrelevant, and will not be used. In particular, this means that field names have to be unique across an entire object definition, and not merely unique within a tab.
<fielddef> |
The <fielddef> element is a complex one, with many possible component elements. There are currently 10 different kinds of fields supported by the Ganymede server, and each of these field types have different options available. The open tag for the fielddef element itself is fairly simple, however. It has just two attributes, both mandatory. These are the same as the ones used in the objectdef tag.. name and id. The contents of the name attribute is limited in precisely the same manner as the name attribute of the objectdef tag's name attribute. It must contain only letters in the standard ASCII set, a-z, the numbers 0-9, a period or dash, and an underscore in place of a space. The id attribute contains the field's number. Numbers between 0 and 99 are reserved for fields that are present in all Ganymede objects, and can only be allocated in the Ganymede server code. Numbers between 100 and 255 are reserved for fields that Ganymede relies on in the pre-defined object types. Numbers between 256 and 32767 are available for user-defined custom field.
Example of the fielddef element's open tag:
<fielddef name="Username" id="100">
The fielddef element can contain a couple of optional elements, comment, and invisible.
The comment element is a text containing element. All text between the opening <comment> tag and the closing </comment> tags is treated as a comment to attach to the field. The Ganymede GUI client will show this text as a pop-up tooltip if the user lets the mouse linger on the GUI component. Aside from some text, however, the comment element should not contain any subelements.
The invisible element is an optional empty element, signifying that the field defined by the containing fielddef element should not be visible in the Ganymede client. This is used to establish invisible scratch fields used by custom code associated with the containing objectdef element for various purposes. This is a rather unusual element to define in a fielddef element, and will only be present in special cases.
Here's a (contrived) example of these two optional elements in use.
<fielddef name="Hidden_Field" id="302"> <comment>This is a hidden field to be used for namespace manipulations.</comment> <invisible/> </fielddef>
Okay, with the two optional elements out of the way, it's time for the meat of the fielddef element, the typedef element. The typedef element specifies what kind of data field the containing fielddef field definition element defines, and has a single attribute, type. The type attribute can have any of the values listed in the following table:
Type | Explanation | Vector Allowed? |
---|---|---|
string | Unicode String | YES |
ip | I.P. Address (either IPv4 or IPv6) | YES |
invid | Object Reference | YES |
boolean | Boolean | NO |
date | Date/Timestamp | NO |
numeric | Integer Number Field | NO |
float | Double precision float | NO |
password | Password Field | NO |
permmatrix | Ganymede Permissions Matrix | NO |
options | Field Options Matrix | NO |
For example:
<typedef type="string">
After the typedef element open tag, there can be a variety of elements, depending on the element's type.
First off, the string, ip, and invid field types can be vector fields, in which a single data field can contain more than one value. In that case, the typedef element will contain a vector element.
The vector element is an empty element with a single attribute, maxSize, which has a numeric value specifying the maximum number of values that can be held in this field at a time. For example,
<typedef type="string"> <vector maxSize="100"/> </typedef>
would describe a vector string field that could contain up to 100 strings in the field. Vector fields in Ganymede can not hold more than 32767 elements, so if no maxSize attribute is defined, an implicit value of 32767 is still in effect.
After the optional vector element (for the string, ip, and invid types only), there are a number of optional field constraint elements which may be present within the <typedef> element. These differ according to the type of the field, and are summarized in the table below. The trickiest options conceptually are those associated with the invid field type. I need to link this material to a general discussion of invid fields.
field type | element name | element details | example | |
---|---|---|---|---|
string | ||||
minlength | The minlegth element is an empty element with a single attribute, val, which contains a numeric value specifying a mandatory minimum number of characters present in this string field. |
<minlength val="2"/> | ||
maxlength |
The maxlength element is an empty element with a single attribute, val, which contains a numeric value specifying the maximum number of characters allowed in this string field. The Ganymede server supports string values of up to 32767 characters in length, and this limit is present implicitly if the maxlength element is not present in a string field definition. |
<maxlength val="8"/> | ||
okchars | The okchars element is an empty element with a single attribute, val, which contains a string value enumerating the characters allowed in this string field. If this optional element is defined in a string typedef element, no characters will be allowed in any field of this type unless that character is present in the val value. |
<okchars val="0123456789-"/> | ||
badchars | The badchars element is an empty element with a single attribute, val, which contains a string value enumerating the characters not allowed in this string field. If this optional element is defined in a string typedef element, a character will not be allowed in any field of this type if that character is present in the val value. |
<badchars val=":"/> | ||
regexp |
The regexp element is an optional empty element with a pair of attributes, one mandatory and one optional. The mandatory attribute is val, which contains a string value which defines a Perl-style regular expression. The optional attribute is desc, which if present will be used as a textual description of the meaning of the regexp. The desc attribute will be provided to the user in an error dialog if they enter a string in the client which does not match the regexp. If no desc attribute is present, the user will be shown the regexp itself in the error message. regexp is an optional element in the string typedef element. If a regexp element is present, all strings entered into fields of this type will be checked against the regexp. The regexp check is made in addition to any okchars and badchars constraints that are defined in the same typedef. |
<regexp val="^[a-z]+[a-z|\d]*$" desc="Usernames may contain letters and numbers, but must begin with a letter."/> | ||
multiline | The multiline element is an empty element with no attributes. This element signifies that this field should be presented in the Ganymede client as a multiline string area rather than a single line text field. |
<multiline/> | ||
namespace | The namespace element is an empty element with a single attribute, val, which contains a string naming a namespace defined in the namespaces element contained in the top-level ganyschema element. If this optional element is defined in a string typedef element, all fields associated with the specified namespace will be constrained to contain unique values across the specified namespace. |
<namespace val="username"/> | ||
ip | ||||
namespace | The namespace element is an empty element with a single attribute, val, which contains a string naming a namespace defined in the namespaces element contained in the top-level ganyschema element. If this optional element is defined in an ip typedef element, all fields associated with the specified namespace will be constrained to contain unique values across the specified namespace. |
<namespace val="IPSpace"/> | ||
invid | ||||
targetobject |
The targetobject element is an empty element with a pair of attributes, name and id, which constrains the type of object this object reference field may point to in the server. The name attribute contains a string which has the encoded (underscores for spaces) name of the object type to point to, while the id attribute contains the integer numberic id of the object type pointed to. Both may be specified, in which case the Ganymede server will verify that both the id number and the object name are consistent, or either one alone may be used. If this invid field is intended to be able to point to any kind of object, this is specified by using the name attribute alone, with a value of "*any*". In this case, no id attribute should be specified. |
<targetobject name="User" id="3"/> | ||
targetfield |
The targetfield element is an optional empty element that specifies the field that this invid field is to be linked with. If a targetfield is specified, the Ganymede server will maintain a symmetric link between this invid field and the target field in objects linked to this field. The target field may be identified using either a name or an id attribute. The name attribute contains a string which has the encoded (underscores for spaces) name of the field to point to, while the id attribute contains the integer numberic id of the field pointed to. Both may be specified, in which case the Ganymede server will verify that both the id number and the field name are consistent, or either one alone may be used. |
<targetfield name="Username" id="103"/> | ||
embedded |
The embedded element is an optional empty element that specifies that this invid field is to be used as an edit-in-place field. That is, that objects linked by this field will be handled as if contained within the object which holds this field. |
<embedded/> | ||
boolean | ||||
labeled | The labeled element is an optional empty element with a pair of attributes, true and false. If this element is present, the client will present this boolean field as a pair of radio buttons rather than a single check-box. This can be useful when you've got a pair of choices that don't fit naturally into a yes/no dichotomy. In general, support for this option has not really been tested, and may not work well. |
<labeled true="Normal User" false="Custom Account"/> | ||
numeric | ||||
namespace | The namespace element is an optional, empty element with a single attribute, val, which contains a string naming a namespace defined in the namespaces element contained in the top-level ganyschema element. If this optional element is defined in a numeric typedef element, all fields associated with the specified namespace will be constrained to contain unique values across the specified namespace. |
<namespace val="uid"/> | ||
password | ||||
minlength | The minlegth element is an empty element with a single attribute, val, which contains a numeric value specifying a mandatory minimum number of characters present in this password field. This element only takes effect when users provide plaintext to the Ganymede server. If the xmlclient or custom client code is used to provide some form of pre-hashed password, this constraint can not be applied. |
<minlength val="2"/> | ||
maxlength |
The maxlength element is an empty element with a single attribute, val, which contains a numeric value specifying the maximum number of characters allowed in this password field. The Ganymede server supports string values of up to 32767 characters in length, and this limit is present implicitly if the maxlength element is not present in a password field definition. This element only takes effect when users provide plaintext to the Ganymede server. If the xmlclient or custom client code is used to provide some form of pre-hashed password, this constraint can not be applied. The crypt encryption hash method supported by Ganymede only considers the first 8 characters of the password in generating the authentication hash, so setting a maxlength larger than 8 characters will not guarantee that Ganymede will require the full password length for login authentication if the crypt method is used. |
<maxlength val="8"/> | ||
okchars | The okchars element is an empty element with a single attribute, val, which contains a string value enumerating the characters allowed in this password field. If this optional element is defined in a password typedef element, no characters will be allowed in any field of this type unless that character is present in the val value. This element only takes effect when users provide plaintext to the Ganymede server. If the xmlclient or custom client code is used to provide some form of pre-hashed password, this constraint can not be applied. |
<okchars val="0123456789-"/> | ||
badchars | The badchars element is an empty element with a single attribute, val, which contains a string value enumerating the characters not allowed in this password field. If this optional element is defined in a password typedef element, a character will not be allowed in any field of this type if that character is present in the val value. This element only takes effect when users provide plaintext to the Ganymede server. If the xmlclient or custom client code is used to provide some form of pre-hashed password, this constraint can not be applied. |
<badchars val=":"/> | ||
cracklib_check |
The cracklib_check element is an optional, empty element. If this element is present, the Ganymede server will use cracklib to perform quality checks on passwords entered in this field. If the attribute 'exception' has the value 'supergash', supergash-level accounts will be given a cracklib warning but will be allowed to ignore the warning. |
<cracklib_check exception="supergash"/> | ||
history_check |
The history_check element is an optional, empty element. If this element is present, the Ganymede server will keep a store of 'depth' hashes for previous passwords that the object has held. If the attribute 'exception' has the value 'supergash', supergash-level accounts will be given a history warning but will be allowed to ignore the warning. |
<history_check exception="supergash" depth="3"/> | ||
crypted |
The crypted element is an optional, empty element. If this element is present, the Ganymede server will store the contents of this password in UNIX crypt() format. |
<crypted/> | ||
md5crypted |
The md5crypted element is an optional, empty element. If this element is present, the Ganymede server will store the contents of this password in FreeBSD-style md5crypt() format. |
<md5crypted/> | ||
apacheMd5crypted |
The apacheMd5crypted element is an optional, empty element. If this element is present, the Ganymede server will store the contents of this password in Apache-style md5crypt() format. |
<apacheMd5crypted/> | ||
winHashed |
The winHashed element is an optional, empty element. If this element is present, the Ganymede server will store the contents of this password in the two Windows NT compatible hash formats used in the Samba encrypted password file. |
<winHashed/> | ||
sshaHashed |
The sshaHashed element is an optional, empty element. If this element is present, the Ganymede server will store the contents of this password in the Salted SHA-1 format used by OpenLDAP. This is Netscape's salted variant of the FIPS SHA-1 standard. SHA-1 is described at http://en.wikipedia.org/wiki/SHA-1, while SSHA is described at http://www.openldap.org/faq/data/cache/347.html. |
<sshaHashed/> | ||
shaUnixCrypted |
The shaUnixCrypted element is an optional, empty element with two optional attributes: type and rounds. If this element is present, the Ganymede server will store the contents of this password in the scalable SHA256/SHA512 Unix Crypt algorithm recently implemented by the GNU C Library on Linux (and which is under consideration for adoption by Sun, IBM, and HP). See http://people.redhat.com/drepper/sha-crypt.html for complete details on this algorithm. Note that this algorithm is only starting to be supported. It works properly on Linux distributions running glibc versions 2.7 and later, such as Fedora 8. Attributes:
|
<shaUnixCrypted type="512" rounds="7500"/> | ||
bCrypted |
The bCrypted element is an optional, empty element with an optional attribute: rounds. If this element is present, the Ganymede server will store the contents of this password using the scalable OpenBSD BCrypt algorithm. Attributes:
|
<bCrypted rounds="15"/> | ||
plaintext |
The plaintext element is an optional, empty element. If this element is present, the Ganymede server will store the plaintext of passwords stored in this field to disk. Normally, if the Ganymede server has any of crypted, md5crypted, apacheMd5crypted, winHashed, sshaHashed, shaUnixCrypted, or bCrypted set, the server will never dump the plaintext of passwords in this field to disk, as it is capable of authenticating logins against any of the supported hash formats. If the plaintext element is present, the password will be preserved in plaintext form in the ganymede.db file, regardless of whether or not the password is also handled via one of the encryption hashes. |
<plaintext/> | ||
options | n/a | The field options field type supports no configurable elements within <typedef> | permmatrix | n/a | The permissions matrix field type supports no configurable elements within <typedef> |
Schema Example Fragment |
The following is a transcript of the User object definition from the GASHARL schema kit in use at ARL. Notable features of this fragment include the Groups invid field which is bidirectionally linked with the Users field in the Groups object type, and the edit-in-place Directory Volume field which contains embedded Embedded Automounter Map Entry objects.
Note also the newline in the middle of the Groups field comment, which is actually preserved faithfully in the Ganymede database.
<objectdef name="User" id="3"> <label fieldid="100"/> <classdef name="arlut.csd.ganymede.gasharl.userCustom"/> <tab name="General"/> <fielddef name="Username" id="100"> <comment>User name for an individual privileged to log into Ganymede and/or the network</comment> <typedef type="string"> <maxlength val="8"/> <badchars val=" :"/> <namespace val="username"/> <regexp val="^[a-z]+[a-z|\d]*$" desc="User names may consist of letters and numbers, but must begin with a letter"/> </typedef> </fielddef> <fielddef name="UID" id="256"> <typedef type="numeric"> <namespace val="uid"/> </typedef> </fielddef> <fielddef name="Password" id="101"> <comment>Password for an individual privileged to log into Ganymede and/or the network</comment> <typedef type="password"> <minlength val="3"/> <maxlength val="32"/> <shaUnixCrypted type="512" rounds="5000"/> <plaintext/> </typedef> </fielddef> <fielddef name="Account_Category" id="273"> <typedef type="invid"> <targetobject name="User_Category"/> </typedef> </fielddef> <fielddef name="Full_Name" id="257"> <typedef type="string"> <maxlength val="64"/> <badchars val=":,"/> </typedef> </fielddef> <fielddef name="Social_Security" id="274"> <typedef type="string"> <okchars val="0123456789-"/> </typedef> </fielddef> <fielddef name="Division" id="258"> <typedef type="string"> <maxlength val="32"/> <badchars val=":,"/> </typedef> </fielddef> <fielddef name="Room" id="259"> <typedef type="string"> <maxlength val="32"/> <badchars val=": ,"/> </typedef> </fielddef> <fielddef name="Office_Phone" id="260"> <typedef type="string"> <maxlength val="16"/> <badchars val=":"/> </typedef> </fielddef> <fielddef name="Home_Phone" id="261"> <typedef type="string"> <maxlength val="16"/> <badchars val=":, "/> </typedef> </fielddef> <fielddef name="Groups" id="264"> <comment>List of non-primary groups the user is a member of. Limited to 16 for NFS.</comment> <typedef type="invid"> <vector maxSize="16"/> <targetobject name="Group"/> <targetfield name="Users"/> </typedef> </fielddef> <fielddef name="Home_Group" id="265"> <typedef type="invid"> <targetobject name="Group"/> <targetfield name="Home_Users"/> </typedef> </fielddef> <fielddef name="Login_Shell" id="263"> <typedef type="string"> <maxlength val="128"/> <badchars val=" :"/> </typedef> </fielddef> <fielddef name="Home_Directory" id="262"> <comment>UNIX default directory, normally assigned by Ganymede</comment> <typedef type="string"> <maxlength val="128"/> <badchars val=" :"/> </typedef> </fielddef> <fielddef name="Admin_Personae" id="102"> <comment>A list of admin personae this user can assume</comment> <typedef type="invid"> <vector/> <targetobject name="Admin_Persona"/> <targetfield name="User"/> </typedef> </fielddef> <fielddef name="Netgroups" id="266"> <typedef type="invid"> <vector/> <targetobject name="User_Netgroup"/> <targetfield name="Users"/> </typedef> </fielddef> <fielddef name="Directory_Volume" id="271"> <typedef type="invid"> <vector/> <targetobject name="Embedded_Automounter_Map_Entry"/> <targetfield name="Containing_Object"/> <embedded/> </typedef> </fielddef> <fielddef name="Email_Aliases" id="267"> <typedef type="string"> <vector/> <maxlength val="32"/> <badchars val="@"/> <namespace val="username"/> </typedef> </fielddef> <fielddef name="Signature_Alias" id="268"> <typedef type="string"> <maxlength val="32"/> <badchars val="@"/> </typedef> </fielddef> <fielddef name="Email_target" id="269"> <typedef type="string"> <vector/> <badchars val=":"/> </typedef> </fielddef> </tab> </objectdef>