DCE H-Cells tools


DCE 1.1 provides hierarchical cells, or H-Cells. One aspect of H-Cells is transitive trust, allowing the RPC/Security run-time to ``walk the org chart'' greatly reducing the number of keys that must be exchanged (and maintained) among cells that wish to communicate. OSF RFC 7.0 provides a good introduction to this facility.

While every cell pair no longer needs to share a key, all cells must currently know the name/uuid of every cell that may communicate with them. We consider it a bug that DCE doesn't do this automatically. It's a hard bug, however, and will probably not be addressed by DCE 1.2.

This message provides some notes on writing dcecp scripts that can be used to partially automate the process. It is also a brief lesson on dcecp scripting. I will take advantage of a few key points:

The TCL catch command can be used to capture the output of a command, and indicate whether or not an error occured. For example:

    set n krbtgt/foo
    catch { principal show $n } prindata

This executes principal show krbtgt/foo command, and stores any output into the variable prindata. It then returns zero if it succeeded or one on error. This lets us write:

    if [ catch { principal show $n } prindata ] {
	# The principal named $n does not exist; must create it.
    }

Now let's fill in the ``must create'' part. Remember we need the name and the uuid. We already have the name in $n. For the UUID I'll use the attrlist command to parse the output of the principal show command:

    set celluuid [ attrlist getvalues $prindata -type uuid ]
    if { $celluuid == "" } {
	#  This is a "can't happen" error.
    }

(The careful reader will see that the two fragments above won't work when put together. If the catch succeeded, the command failed, so prindata will be empty.)

Note that attrlist getvalues returns an empty string if the type isn't found. All DCE principals have a uuid, so I'm on the verge of paranoia by doing the error-checking. We can then put the two fields together and create the cell principal:

    principal create $n -uuid $celluuid

The only remaining part is how to get the ``definitive'' list of all cells. This will depend on how you set up DCE in your enterprise. I'll show some alternatives below.

You might want to create a cron job that runs the script. (This will mean embedding the DCE password somewhere, which is not good, but there are no alternatives to this now.)

Now we can build up the pieces. Let's assume that other_cell is the name of a parent (or sibling) cell using the global ``/.../foo'' notation. We want to know about all cells that that cell knows about. The following loop gives us the names of all cell principals known by that other cell:

    foreach p [ principal catalog $other_cell -simplename ] {
	##  Is this a cell principal that we don't know about?
        if { [ string match krbtgt/* $p ] && [ catch { principal show $p } ] } {
            # Yes.  Find the cell's uuid and create the principal here.
            set output [ principal show $other_cell/$p ]
            set celluid [ attrlist getvalues $output -type uuid ]
	    principal create $p -uuid $celluuid
        }
    }

Now let's make this into a function:

   proc get_prins_from_cell { other_cell } {
       foreach p [ principal catalog $other_cell -simplename ] {
           # Is this a cell principal that we don't know about?
           if { [string match krbtgt/* $p] && [catch {principal show $p}] } {
               # Yes.  Find the cell's uuid and create locally.
               set output [ principal show $other_cell/$p ]
               set celluid [ attrlist getvalues $output -type uuid ]
               principal create $p -uuid $celluuid
           }
       }
   }

The last question to answer is how to set other_cell. Here are a couple of ideas. They all follow the same format: a loop around the function above.

One simple method is to ask all the cells you already know about for the cells that they know about. The key here is using the TCL regexp command. This does a regular-expression match and returns one if the string matched, or zero if it didn't. As a side-effect it can also set a variable to part of the string that was matched. In our case, we want to see if the principal name looks like ``krbtgt/foo'' and, if so, set a variable to hold the foo part:

    foreach p [ principal catalog -simplename ] {
	if [ regexp "krbtgt/(.*)" $p other_cell ] {
	    get_prins_from_cell /.../$other_cell
	}
    }

This method is not very efficient. A better method might be for a cell to know only its parent. A script can find the name of its cell from a well-known hostdata object:

    set mycellname [
	attrlist getvalues [ hostdata show cell_name ] -type hostdata/data
    ]

It can then use regexp command to strip off the last component. Note that I used {} to quote the pattern, not "" marks since the pattern has [] characters in it:

    if [ regexp {(/.../.*)/([^/]*)} $mycellname temp parent ] {
	# The name of the parent cell is now in $parent
	get_prins_from_cell $parent
    }

You could also hardwire a set of cell names and try that:

    foreach cell { /.../foo /.../foo/bar /.../foo/mis } {
	get_prins_from_cell $cell
    }

Even simpler, you can assume/ensure that there is one cell in your enterprise that knows about every other cell. For example, you can create your own cell-creation script that exchanges keys with this enterprise keymaster cell. (It might be a good idea to make this cell be your root cell.)

   get_prins_from_cell /.../enterprise_cell

Hope you find this useful. Note that since I only used dcecp, the script fragments here are portable to any DCE platform that provides dcecp.