This document describes the file format of the protection database file. The actual prdb.DB0 file on disk begins with a ubik header, which is not exposed to the callers of ubik_ RPCs. 64 octets are reserved for this header, though only 16 are used. The first 16 octets contain the representation of a struct ubik_hdr, with all fields in network byte order: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ubik_magic | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | padding | header_size | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | epoch | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | counter | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [unused] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [unused] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [unused] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [unused] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [unused] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [unused] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [unused] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [unused] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [unused] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [unused] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [unused] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [unused] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 ubik_magic is a global constant, 0x00354545. padding is an unused field and should always be zeros. header_size is the length of the reserved space for the ubik header, and will always be 0x64. epoch is the ubik epoch. counter is the ubik counter for transactions and updates. The unused space should always be zeros. The ubik header is not exposed through the PR_ RPC package, and as such is not considered to be part of the logical prdb database. Subsequent discussion will refer to addresses and offsets; these addresses are logical addresses within the prdb, and do not include the size of the ubik header. When using logical addresses to index into the file on disk, the size of the ubik header must be added to the offset used. Immediately following the ubik header on disk (so, at the beginning of the logical prdb) is the prdb header, which consumes 65600 octets. The majority of this space is for two hash tables, enabling quick lookups of prdb entries by name and by id. All fields with integer values are stored in network byte order. The prdb header structure is: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 octets +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 0 | version | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | headerSize | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | freePtr | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | eofPtr | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | maxGroup | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | maxID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | maxForeign | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | maxInst | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 32 | orphan | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | usercount | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | groupcount | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | foreigncount | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | instcount | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [reserved] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [reserved] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [reserved] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 64 | [reserved] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [reserved] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 72 | nameHash | | | ~ ... ~ 32832 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 32836 | idHash | | | ~ ... ~ 65596 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 version is the PR database version number. Only version number 0 is presently in use. headerSize is the size in octets of the prdb header (currently 0x10040). freePtr is the logical index (in octets) of the first unused prentry in the prdb (that is, the first logical hole in the database file). If the database file is densely packed, this field is zero. This index is not the actual index into the prdb.DB0 file on disk, because logical indices within the prdb do not account for the 64-octet space reserved for the ubik header. eofPtr is the index (in octets) of the end of the database file. When a new entry is created that extends the database file, it will be created at this logical index. (Again, this logical index excludes the 64-octet ubik header.) maxGroup is the most negative group ID allocated, stored as a 32-bit twos-complement signed integer. maxId is the largest user ID allocated to a local-realm user. maxForeign is the largest user ID allocated to a foreign-realm user. maxInst is reserved for a feature which is not yet implemented. orphan is the pointer to the head of the list of "orphaned" prdb entries. Entries are orphaned when their owner gets deleted; at that time, they are added to the head of the orphan list. usercount is the number of user entries in the prdb. groupcount is the number of group entries in the prdb, including mandatory groups such as system:backup, system:administrators, system:ptsviewers, system:authuser, and system:anyuser. foreigncount is the number of foreign users that have registered with the prdb. instcount is reserved for a feature which is not yet implemented. Five 32-bit fields are reserved for future expansion. The nameHash and idHash fields each contain 8191 entries; each entry is 32 bits, so the space consumed by each hash table is 32764 octets. The NameHash hash function is targetted for ASCII text. Each octet is treated as an unsigned integer from which 31 (decimal) is subtracted (corresponding to the 7-bit control characters), and the resulting stream of integers is used as the coefficients of a power series with base 31 (also decimal), with the least significant coefficient appearing first. For example, if a name string was the (highly unlikely and nigh-unusable) stream of octets (in hex): 21 22 23 24 Then the power series used in the hash function calculation would be (all numbers in decimal): 2 + 3 * 31 + 4 * 31**2 + 5 * 31**3 The value of this power series is stored in an unsigned 32-bit integer, and as such is implicitly computed modulo 2**32. The remainder modulo 8191 (the size of the hash table) of this 32-bit value is used as the index into the hash table for this name entry. (This hash function can be easily implemented iteratively.) The IdHash hash function is very simple; it is just the remainder modulo 8191 (the size of the hash table) of the absolute value of the user or group id. Note that a group id of INT_MIN would cause undefined behavior in the evaluation of this hash function, and is given the name PRBADID and used as a sentinel. Hash collisions are treated in the standard way of having a linked list of entries with the same hash. The hash table itself holds the id of the entry which is the head of the list, and the nextName and nextID fields of each entry chain the lists for the respective hash tables. prdb entries follow immediately after the prdb header. Each entry is 192 octets in size, and may represent either a user or a group or (if enabled) a supergroup entry, or a continuation entry. User and group entries use the same format for the data structure (user ids are positive and group ids are negative, and their structures parallel each other), and continuation entries are used when a user belongs to more than PRSIZE (10) groups or a group has more than PRSIZE users in it. supergroup entries share many fields with the user/group entries, but the binary format is slightly different. In all cases, integer fields are represented in network byte order. All entries have a flags field in the second 16 bits which is used to indicate what type the entry is -- PRFREE, PRGRP, PRCONT, PRCELL, PRFOREIGN, or PRINST (not used). The other fields which are invariant in the block structure (i.e., present in all types of entry) are id, cellid, and next. At present there is also a reserved field in all entry types at a fixed offset; this field can be used for future extensions. Another invariant is that each block (outside the header) is pointed to from some other location. Continuation blocks are pointed to from the 'next' field of the previous block, and user/group entries are locatable from the name and id hash tables, either directly from the header or through a nextName/nextID pointer. The head of the free list is in the prdb header directly. The layout of the invariant fields is: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 octets +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 0 | [entry-specific] | type_flags | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | id | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cellid | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | next | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 16 | [entry-specific] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [entry-specific] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [entry-specific] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [entry-specific] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 32 | reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ type_flags specifies the type of this prdb entry: 0x1 PRFREE -- the entry is on the free list 0x2 PRGRP -- the entry is a group entry 0x4 PRCONT -- the entry is a continuation block 0x8 PRCELL -- the entry is a cell entry 0x10 PRFOREIGN -- the entry is for a foreign user 0x20 PRINST -- the entry is a sub/super instance 0x3f PRTYPE -- bitmask for "type" bits Other bits are allocated for status flags on the entry: 0x40 PRACCESS -- access checking is enabled 0x80 PRQUOTA -- group creation quota checking is enabled Note that this document specifies the on-disk data format, which is in network byte order. Because the fundamental quantum of ubik accesses is a 32-bit word, byte swaps between host and network byte order are done on 32-bit words, so the in-memory representation may place the bits holding type_flags in the other half of the word. id is the ID number of the user or group, or the user/group to which an continuation or other extension entry belongs. User entries are positive and group entries are negative. cellid is only used for foreign user entries (not foreign groups). Group entries are allocated for system:authuser@remotecell with a (negative 32-bit) group id of a particular substructure. Foreign user entries have their cellid field set to the id of the system:authuser@remotecell group corresponding to the remotecell of the foreign user. (Additionally, foreign user entries are allocated pts ids with a particular substructure.) There is no particularly good reason for the cellid field to remain an invariant in future extensions. next is a pointer to the next entry in a chain of related data for this entry, e.g. a continuation block. For type PRFREE entries, it is a pointer to the next block on the free list. The layout of a user or group entry (struct prentry) is: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 octets +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 0 | prp_flags | type_flags | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | id | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cellid | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | next | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 16 | createTime | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | addTime | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | removeTime | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | changeTime | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 32 | reserved0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | entries[0] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | entries[1] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | entries[2] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 48 | entries[3] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | entries[4] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | entries[5] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | entries[6] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 64 | entries[7] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | entries[8] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | entries[9] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | nextID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 80 | nextName | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | owner | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | creator | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ngroups | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 96 | nusers | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | count | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | instance | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | owned | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 112 | nextOwned | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | parent | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | sibling | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | child | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 128 | name | + + | | + + | | + + | | + + 144 | | + + | | + + | | + + | | + + 160 | | + + | | + + | | + + | | + + 176 | | + + | | + + | | + + 188 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 prp_flags and type_flags are consolidated into a single "flags" field for API purposes. prp_flags hold the access bits for entries, e.g., PRP_STATUS_ANY and PRP_ADD_MEM. Because prp_flags and type_flags are consolidated into a single 'flags' field for the API, the in-memory layout will have prp_flags and type_flags swapped on little-endian machines. [id and cellid are per the entry-invariant fields] next is a pointer to the next continuation block for this entry, or (for type PRFREE entries) a pointer to the next block on the free list. createTime holds the time at which this entry was created, in seconds from the Unix epoch. addTime is the most recent time at which an entry was added to this usr/group's membership list, in seconds since the Unix epoch. removeTime is the most recent time at which an entry was removed from this user/group's membership list, in seconds since the Unix epoch. changeTime is the most recent time at which the entry was changed with a PR_ChangeEntry RPC (that is, renamed or renumbered or had owner or name change). Changing the access flags does not update this time. reserved[0] is reserved for future use. entries[0-9] hold the first ten elements of this entry's membership list (the users in this group, or the groups of which this user is a member). They are populated in increasing order; when fewer than ten elements are present, the unused fields are zero or PRBADID. Additional elements of the membership list are stored in continuation block(s). nextID is a pointer for the hash table chain in the header's idHash hash table. All prdb entries whose id hashes to the same value are stored in a singly-linked list; this field effects the linkage of that list. nextName is similar to nextID, but for the nameHash hash table instead of the idHash hash table. owner is the id of the the prdb entry which owns this entry. creator is the id of the prdb entry which created this entry. ngroups is the number of groups this entry is still allowed to create (it is the quota minus the number of groups which have been created). For regular group entries, this field is always zero. For foreign group entries, this is the number of (foreign) users who are members of that group. nusers is nominally the foreign user registration quota for a user entry, that is, the number of foreign user entries this user is still allowed to create. However, this quota value is never actually used -- the presence of nusers for user entries was intended to support a feature which has not been implemented. For regular group entries, it is always zero. For foreign group entries (i.e., system:authuser@remotecell), nusers is the number of foreign user entries which are members of the group. (It is used when allocating user ids for new foreign users from that cell.) count is the cardinality of this entry's membership list. That is, for user entries, the number of groups of which this user is a member; for group entries, the number of users in the group. instances is reserved for a feature which is not yet implemented. owned is the head of the linked list of entries owned by this entry. Both users and groups may own group entries (user entries always display as being owned by system:administrators though the numerical value of this field is zero). The nextOwned field of the group entries chains this list. nextOwned is the pointer to the next entry in the list of groups owned by a the owner of this group. For user entries, this field is always zero. parent is reserved for a feature which is not yet implemented. sibling is reserved for a feature which is not yet implemented. child is reserved for a feature which is not yet implemented. name holds the name of this entry. For users, it is the krb4 name; for groups, is is an ASCII string. The name is NUL-terminated, making the maximum permissible length of a name 63 characters. Unused portions of this field should be zeroed. Supergroup entries are quite similar to regular user/group entries, differing only at the 'instance', 'parent', 'sibling', and 'child' fields, which are replace by 'countsg', 'nextsg', 'supergroup[0]', and 'supergroup[1]', respectively. Putting the byte offsets in, those fields are: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 octets +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 104 | countsg | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | owned | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 112 | nextOwned | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | nextsg | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | supergroup[0] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | supergroup[1] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 128 | name | ~ ~ 188 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 countsg is the number of groups of which this group is a member, akin to the 'count' field of a user entry. nextsg is a pointer to a chain of continuation blocks holding additional supergroup entries for this group. That is, the 'entries' elements of the continuation blocks will be groups of which this group is a member, akin to supergroup[0-1]. This chain is extended using the 'next' pointer of the contentry structure, if necessary. supergroup[0-1] are the first two groups of which this group is a member. These supergroup elements are used in increasing order, and unused elements should be zero (but PRBADID is also okay). Continuation entries have a simpler structure, retaining a few key fields that are shared amongst all types of entry but leaving a large contiguous block of space to be used as an array of ids. Again, all integer fields are stored in network byte order. The format is: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 octets +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 0 | unused | type_flags | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | id | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | cellid | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | next | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 16 | reserved[0] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | reserved[1] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | reserved[2] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | reserved[3] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 32 | reserved[4] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | entries[0] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | entries[1] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | entries[2] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 48 | entries[3] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ~ ... ~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 188 | entries[38] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 0 1 2 3 the type_flags field is again exposed via the API as a 32-bit 'flags' field, but only the low 16 bits are used for flags by continuation entries. id and cellid are retained as a consistency check for the entry -- these fields should be identical amongst the main entry and all continuation blocks chained to it. The four Time fields present in the user/group entries are not needed for continuation entries, but are left as reserved so as to make the space used for holding ids a contiguous array. Each continuation block can hold up to 39 additional prdb ids associated with the original user or group entry, extending the original 10 entries available in the main entry block (for user/group membership) or the original 2 entries available in the main group block (for supergroup membership).