The secpol_resmgr_attach() and resmgr_attach() functions and their parameters
As you saw in the /dev/null example above, the first thing you'll
want to do is register your chosen mountpoint
with the process manager. This is done via
secpol_resmgr_attach() or resmgr_attach().
int secpol_resmgr_attach (secpol_file_t *handle,
void *dpp,
resmgr_attr_t *resmgr_attr,
const char *path,
enum _file_type file_type,
unsigned flags,
const resmgr_connect_funcs_t *connect_funcs,
const resmgr_io_funcs_t *io_funcs,
iofunc_attr_t *iofunc_attr,
bool *perms_set);
The prototype for resmgr_attach() functions is the same, except it does not have the secpol_file_t handle or perms_set parameters.
Let's examine these arguments, in order, and see what they're used for.
- handle
-
Handle to the security policy file. Usually NULL, which specifies that the default security policy file is used (either the system default or one set using secpol_open()).
- dpp
- The dispatch handle. This lets the dispatch interface manage the message receive for your resource manager.
- resmgr_attr
- Controls the resource manager characteristics, as discussed above.
- path
- The mountpoint that you're registering. If you're registering a discrete mountpoint (such as would be the case, for example, with /dev/null, or /dev/ser1), then this mountpoint must be matched exactly by the client, with no further pathname components past the mountpoint. If you're registering a directory mountpoint (such as would be the case, for example, with a network filesystem mounted as /nfs), then the match must be exact as well, with the added feature that pathnames past the mountpoint are allowed; they get passed to the connect functions stripped of the mountpoint. For example, the pathname /nfs/etc/passwd would match the network filesystem resource manager, and it would get etc/passwd as the rest of the pathname.
- file_type
- The class of resource manager. See below.
- flags
- Additional flags to control the behavior of your resource manager. These flags are defined below.
- connect_funcs and io_funcs
- These are simply the list of connect functions and I/O functions that you wish to bind to the mountpoint.
- iofunc_attr
- This is an
extendable
data structure (akaattributes structure
) that identifies the resource being mounted. For example, for a serial port, you'd extend the standard POSIX-layer attributes structure by adding information about the base address of the serial port, the baud rate, etc. - perms_set
-
If non-NULL, set to
true
if permissions were altered; otherwise, set tofalse
.
The flags member can contain any of the following flags (or the constant 0 if none are specified):
- _RESMGR_FLAG_BEFORE or _RESMGR_FLAG_AFTER
- These flags indicate that your resource manager wishes to be placed before or after (respectively) other resource managers with the same mountpoint. These two flags would be useful with unioned (overlaid) filesystems. We'll discuss the interactions of these flags shortly.
- _RESMGR_FLAG_DIR
- This flag indicates that your resource manager is taking over the specified mountpoint and below—it's effectively a filesystem style of resource manager, as opposed to a discretely manifested (device) resource manager.
- _RESMGR_FLAG_OPAQUE
- If set, prevents resolving to any other manager below your mountpoint except for the path manager. This effectively eliminates unioning on a path.
- _RESMGR_FLAG_FTYPEONLY
- This ensures that only requests that have the same _FTYPE_* as the file_type passed to resmgr_attach() are matched.
- _RESMGR_FLAG_FTYPEALL
- This flag is used when a resource manager wants to catch all client requests, even those with a different _FTYPE_* specification than the one passed to resmgr_attach() in the file_type argument. This can only be used in conjunction with a registration file type of _FTYPE_ALL.
- _RESMGR_FLAG_SELF
- Allow this resource manager to talk to itself.
This really is a
Don't try this at home, kids
kind of flag, because allowing a resource manager to talk to itself can break the send-hierarchy and lead to deadlock (as was discussed in the Message Passing chapter).
You can call secpol_resmgr_attach() or resmgr_attach()
multiple times to mount different mountpoints. You can also call them from within the
connect or I/O functions—this is kind of a neat feature that allows you to
create
devices on the fly.
For more information, go to the entry procmgr_ability() in the QNX OS C Library Reference.
When you've decided on the mountpoint, and want to create it, you'll need to
tell the process manager if this resource manager can handle requests from just
anyone, or if it's limited to handling requests only from clients who identify
their connect messages with special tags.
For example, consider the POSIX message queue
(mqueue)
driver.
It's not going to allow (and certainly wouldn't know what to do with) regular
open() messages from any old client.
It will allow messages only from clients that use the POSIX
mq_open(),
mq_receive(),
and so on, function calls.
To prevent the process manager from even allowing regular requests to arrive at the mqueue resource manager, mqueue specified _FTYPE_MQUEUE as the file_type parameter. This means that when a client requests a name resolution from the process manager, the process manager won't even bother considering the resource manager during the search unless the client has specified that it wants to talk to a resource manager that has identified itself as _FTYPE_MQUEUE.
Unless you're doing something very special, you'll use a file_type of _FTYPE_ANY, which means that your resource manager is prepared to handle requests from anyone. For the full list of _FTYPE_* manifest constants, take a look in <sys/ftype.h>.
With respect to the before
and after
flags, things
get a little bit more interesting.
You can specify only one of these flags or the constant 0.
Let's see how this works. Suppose a number of resource managers have started, in the order given in the table. We also see the flags they passed for the flags member. Observe the positions they're given:
Resmgr | Flag | Order |
---|---|---|
1 | _RESMGR_FLAG_BEFORE | 1 |
2 | _RESMGR_FLAG_AFTER | 1, 2 |
3 | 0 | 1, 3, 2 |
4 | _RESMGR_FLAG_BEFORE | 1, 4, 3, 2 |
5 | _RESMGR_FLAG_AFTER | 1, 4, 3, 5, 2 |
6 | 0 | 1, 4, 6, 3, 5, 2 |
As you can see, the first resource manager to actually specify a flag always
ends up in that position.
(From the table, resource manager number 1 was the first to specify the before
flag; no matter who registers, resource manager 1 is always first in the list.
Likewise, resource manager 2 was the first to specify the after
flag; again, no matter who else registers, it's always last.)
If no flag is specified, it effectively acts as a middle
flag.
When resource manager 3 started with a flag of zero, it got put into the middle.
As with the before
and after
flags,
there's a preferential ordering given to all the middle
resource managers, whereby newer ones are placed in front of other, existing middle
ones.
However, in reality, there are very few cases where you'd actually mount more
than one, and even fewer cases where you'd mount more than two resource managers
at the same mountpoint.
Here's a design tip: expose the ability to set the
flags at the command line of the resource manager so that the end-user of
your resource manager is able to specify, for example, -b
to use the before
flag, and -a to use the after
flag, with no command-line option specified to indicate that a zero should be
passed as the flag.
Keep in mind that this discussion applies only to resource managers
mounted with the same mountpoint.
Mounting /nfs
with a before
flag and /disk2
with an after
flag will have no effect on each other; only if you were to then
mount another /nfs
or
/disk2
would these flags (and rules)
come into play.
Finally, the secpol_resmgr_attach() and resmgr_attach() functions return a small integer handle on success or -1 on failure. This handle can then be used to detach the pathname from the process manager's internal pathname tables.