/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <syslog.h>
#include "automount.h"
#include "ns_fnutils.h"
/*
* The maximum sizes of map names, key names, composite names, and status
* descriptions, including the trailing '\0'.
*/
/*
* The name of an attribute.
*/
/*
* Given a request by a particular user to mount the name "key" under
* "res") either a list of mapents giving the mounts that need to be
* performed, or a symbolic link to be created for a user-relative
* context. If "shallow" is true return, in place of the list of
* mapents, a single mapent representing an indirect mount point.
*
* void
* getmapent_fn(char *key, char *map, char *opts, uid_t uid,
* bool_t shallow, getmapent_fn_res *res);
*/
/*
* Given a reference, its composite name, default mount options, and a
* mapent root, return a list of mapents to mount. If "shallow" is
* true return, in place of the list of mapents, a single mapent
* representing an indirect mount point. The map and key strings are
* pieces of the composite name such that:
*/
static mapent *
/*
* Traverse the namespace to find a frontier below ref along which
* future mounts may need to be triggered. Add to mapents the
* corresponding direct autofs mount points.
* map: map name for ref
* maplen: strlen(map)
* mntpnt: suffix of map where the current mount request begins
* (starts off as "", and grows as we traverse the namespace)
* opts: default mount options
* status: passed from above to avoid having to allocate one on each call
* Works by calling frontier_aux() on each name bound under ref.
* Return the new mapents, or free mapents and return NULL on failure.
*/
static mapent *
/*
* Called by frontier(), once for each "name" that it finds. map is
* passed unchanged from frontier(). ref is the reference named by
* corresponding direct autofs mount point to mapents. Otherwise
* continue traversing the namespace to find the frontier. Other
* arguments and the return value are as for frontier().
*/
static mapent *
/*
* Given a reference with an address type of ADDR_HOST and its
* composite name, check the attr_exported attribute to determine if
* the corresponding directory is exported. Return FALSE on error.
*/
static bool_t
/*
* Find a reference's address type and, if "data" is not NULL, its
* data string. If there is no address of a known type, set *typep to
* NUM_ADDRTYPES; if there are several, stop after finding the first.
* Return 0 on success.
*/
static int
/*
* Decode an address's data into a string. Return 0 on success.
*/
static int
/*
* Given a map name and its current length, append "/name". Return
* the new length. On error, syslog a warning and return 0.
*/
static size_t
/*
* Concatenate two strings using the given separator. The result is a
* newly-allocated string, or NULL on error.
*/
static char *
/*
* Add the "nosuid" option to a mapent. Also check for a sneaky
* hacker trying to override this option by manually inserting a
* multiple mount entry into the XFN namespace. Return FALSE on error.
*/
static bool_t
/*
* Append "nosuid" to a list of options. The result is a
* newly-allocated string, or NULL on error.
*/
static char *
/*
* Trim comments and trailing whitespace from ml->linebuf, then
* unquote it and leave the result in ml. Return 0 on success.
*/
static int
/*
* Determine whether ml contains an option string (such as "-ro") and
* nothing else.
*/
static bool_t
/*
* Allocate a new mapent structure. The arguments must have been
* malloc'ed, and are owned by the mapent; they are freed if
* new_mapent() fails. If any argument is NULL, the call fails and a
* memory allocation failure is logged. A root argument of 'noroot'
* indicates that the map_root field does not need to be set (it's
* only needed in the first of a list of mapents).
*/
static mapent *
char *dir);
/*
* Determine whether cname is a user-relative binding -- such as "myself" --
* in the initial context.
*/
static bool_t
is_user_relative(const char *cname);
/*
* Given the name of a user-relative binding, return an equivalent
* name that is not user-relative.
*/
static char *
void
{
int statcode;
char *root;
if (init_fn() != 0) {
return;
}
/*
* For direct mounts, the key is the entire path, and the map
* name already has the final key component appended. Split
* apart the map name and key. The "root" of the mapent is
* "/key" for indirect mounts, and "" for direct mounts.
*/
if (key[0] == '/') {
} else {
}
if (verbose) {
}
return;
}
if (maplen == FNPREFIXLEN) {
} else {
}
status = fn_status_create();
if (verbose) {
}
return;
}
goto done;
}
#ifndef XFN1ENV
if (is_user_relative(cname)) {
goto done;
}
#endif
goto done;
}
}
if ((statcode != FN_E_NAME_NOT_FOUND) &&
(statcode != FN_E_NOT_A_CONTEXT)) {
}
goto done;
}
done:
}
static mapent *
{
char *homedir;
char *colon;
char *nfshost;
char *nfsdir;
switch (addrtype) {
case ADDR_MOUNT:
return (NULL);
}
/* parse_entry() can't handle such lines */
"%s/%s: opts too long (max %d chars)",
return (NULL);
}
goto indirect;
}
TRUE);
return (NULL);
}
break;
case ADDR_HOST:
/*
* Address is of the form "host:dir".
* If "dir" is not supplied, it defaults to "/".
*/
} else {
*colon = '\0';
}
/*
* If nfshost is the local host, the NFS mount
* request will be converted to a loopback
* mount. Otherwise check that the file system
* is exported.
*/
return (NULL);
} else {
goto indirect;
}
}
}
return (mapents);
}
break;
case ADDR_USER:
break;
}
return (NULL);
}
if (shallow) {
goto indirect;
}
return (mapents);
}
}
/* Ref type wasn't recognized. */
/* Install an indirect autofs mount point. */
}
/*
* All that this function really does is call frontier_aux() on every
* name bound under ref. The rest is error checking(!)
*
* The error handling strategy is to reject the entire mount request
* (by freeing mapents) if any (potentially) transient error occurs,
* and to treat nontransient errors as holes in the affected portions
* of the namespace.
*/
static mapent *
{
const char *child;
unsigned int statcode;
}
goto checkerr_return;
}
goto checkerr_return;
}
!= NULL) {
if (verbose) {
"FNS string error listing %s", map);
}
goto err_return;
}
goto noerr_return;
}
}
if (fn_status_is_success(status)) {
goto noerr_return;
} else {
/* Fall through to checkerr_return. */
}
goto noerr_return;
}
return (mapents);
}
static mapent *
{
/*
* We could instead install an indirect autofs mount point
* here. That would allow, for example, a user to be bound
* beneath a file system.
*/
return (mapents);
}
return (mapents);
}
if (trace > 1) {
}
/*
* If this is an address type that we know how to mount, then
* we have reached the frontier.
*/
/*
* For an ADDR_HOST address, treat a non-exported directory as
* if the address type were not known: continue searching for
* exported subdirectories.
*/
return (NULL);
} else {
at_frontier = FALSE;
}
}
}
/*
* If we have reached the frontier, install a direct autofs
* mount point (which will trigger the actual mount if the
* user steps on it later). Otherwise, continue traversing
* the namespace looking for known address types.
*/
if (at_frontier) {
: strdup("direct");
/* Link new mapent into list (not at the head). */
} else {
}
} else {
mapents =
}
return (mapents);
}
static bool_t
{
return (FALSE);
}
switch (fn_status_code(status)) {
case FN_SUCCESS:
break;
case FN_E_NO_SUCH_ATTRIBUTE:
break;
default:
}
}
static int
{
void *iter_pos;
if (verbose) {
}
return (-1);
}
if (*typep < NUM_ADDRTYPES) {
: 0);
}
}
return (-1);
}
static int
{
int res;
if (verbose) {
"Could not decode FNS address for %s", cname);
}
res = -1;
} else {
res = 0;
}
xdr_destroy(&xdr);
return (res);
}
static size_t
{
if (verbose) {
}
return (0);
}
}
static char *
{
if (s != NULL) {
}
return (s);
}
static bool_t
{
char *opts;
/* Multiple mounts don't belong in XFN namespace. */
return (NULL);
}
}
static char *
{
char *start;
if (opts[0] == '\0') {
return (strdup(MNTOPT_NOSUID));
}
/* A quick-and-dirty check to see if "nosuid" is already there. */
start--;
}
}
}
}
static int
{
end--;
}
return (-1);
}
*end = '\0';
return (0);
}
static bool_t
{
if (*s != '-') {
return (FALSE);
}
for (; *s != '\0'; s++, q++) {
if (isspace(*s) && (*q == ' ')) {
return (FALSE);
}
}
return (TRUE);
}
static mapent *
char *dir)
{
}
return (NULL);
}
return (me);
}
#ifndef XFN1ENV
/*
* User-relative bindings in the initial context, and the leading components
* of their non-user-relative equivalents. Leading components are listed in
* the order in which they should be tried. Each list is NULL-terminated
* (the compiler generously does this for us).
* For "myorgunit", for example, we first check if it is equivalent to
* "thisorgunit". If not, we translate it into "org/<something>".
*/
static struct {
const char *binding;
} user_rel[] = {
{"thisuser", {"user", "thisorgunit", "org"}},
{"myself", {"user", "thisorgunit", "org"}},
{"_myself", {"_user", "_thisorgunit", "_orgunit"}},
{"myorgunit", {"thisorgunit", "org"}},
{"_myorgunit", {"_thisorgunit", "_orgunit"}},
{"myens", {"thisens"}},
{"_myens", {"_thisens"}}
};
static bool_t
{
int i;
return (TRUE);
}
}
return (FALSE);
}
static char *
{
const char *equiv_str;
char *equiv_str_dup;
const char **leads;
unsigned int stat;
int i;
break;
}
}
return (NULL);
}
do {
if (leading_name == NULL) {
return (NULL);
}
status);
}
return (NULL);
}
if (equiv_string == NULL) {
return (NULL);
}
return (NULL);
}
return (equiv_str_dup);
}
#endif /* XFN1ENV */