Example #1
0
/**
 * @brief Validate export permissions
 *
 * @param[in]  req              Incoming request.
 *
 * @return NFS4_OK if successful, NFS4ERR_ACCESS or NFS4ERR_WRONGSEC otherwise.
 *
 */
nfsstat4 nfs4_export_check_access(struct svc_req *req)
{
    xprt_type_t xprt_type = svc_get_xprt_type(req->rq_xprt);
    int port = get_port(op_ctx->caller_addr);

    LogMidDebugAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT,
                   "nfs4_export_check_access about to call export_check_access");
    export_check_access();

    /* Check if any access at all */
    if ((op_ctx->export_perms->options &
            EXPORT_OPTION_ACCESS_TYPE) == 0) {
        LogInfoAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT,
                   "Access not allowed on Export_Id %d %s for client %s",
                   op_ctx->export->export_id,
                   op_ctx->export->fullpath,
                   op_ctx->client
                   ? op_ctx->client->hostaddr_str
                   : "unknown client");
        return NFS4ERR_ACCESS;
    }
Example #2
0
/**
 * @brief Validate export permissions
 *
 * @param[in]  req              Incoming request.
 *
 * @return NFS4_OK if successful, NFS4ERR_ACCESS or NFS4ERR_WRONGSEC otherwise.
 *
 */
nfsstat4 nfs4_export_check_access(struct svc_req *req)
{
	xprt_type_t xprt_type = svc_get_xprt_type(req->rq_xprt);
	int port = get_port(op_ctx->caller_addr);

	LogMidDebugAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT,
		    "nfs4_export_check_access about to call export_check_access");
	export_check_access();

	/* Check if any access at all */
	if ((op_ctx->export_perms->options &
	     EXPORT_OPTION_ACCESS_MASK) == 0) {
		LogInfoAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT,
			"Access not allowed on Export_Id %d %s for client %s",
			op_ctx->ctx_export->export_id,
			op_ctx->ctx_export->fullpath,
			op_ctx->client
				? op_ctx->client->hostaddr_str
				: "unknown client");
		return NFS4ERR_ACCESS;
	}

	/* Check protocol version */
	if ((op_ctx->export_perms->options & EXPORT_OPTION_NFSV4) == 0) {
		LogInfoAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT,
			"NFS4 not allowed on Export_Id %d %s for client %s",
			op_ctx->ctx_export->export_id,
			op_ctx->ctx_export->fullpath,
			op_ctx->client
				? op_ctx->client->hostaddr_str
				: "unknown client");
		return NFS4ERR_ACCESS;
	}

	/* Check transport type */
	if (((xprt_type == XPRT_UDP) &&
	    ((op_ctx->export_perms->options &
	      EXPORT_OPTION_UDP) == 0))
	    ||
	    ((xprt_type == XPRT_TCP) &&
	    ((op_ctx->export_perms->options &
	      EXPORT_OPTION_TCP) == 0))) {
		LogInfoAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT,
			"NFS4 over %s not allowed on Export_Id %d %s for client %s",
			xprt_type_to_str(xprt_type),
			op_ctx->ctx_export->export_id,
			op_ctx->ctx_export->fullpath,
			op_ctx->client
				? op_ctx->client->hostaddr_str
				: "unknown client");
		return NFS4ERR_ACCESS;
	}

	/* Check if client is using a privileged port. */
	if (((op_ctx->export_perms->options &
	      EXPORT_OPTION_PRIVILEGED_PORT) != 0)
	    && (port >= IPPORT_RESERVED)) {
		LogInfoAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT,
			"Non-reserved Port %d is not allowed on Export_Id %d %s for client %s",
			port, op_ctx->ctx_export->export_id,
			op_ctx->ctx_export->fullpath,
			op_ctx->client
				? op_ctx->client->hostaddr_str
				: "unknown client");
		return NFS4ERR_ACCESS;
	}

	/* Test if export allows the authentication provided */
	if (export_check_security(req) == false) {
		LogInfoAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT,
			"NFS4 auth not allowed on Export_Id %d %s for client %s",
			op_ctx->ctx_export->export_id,
			op_ctx->ctx_export->fullpath,
			op_ctx->client
				? op_ctx->client->hostaddr_str
				: "unknown client");
		return NFS4ERR_WRONGSEC;
	}

	/* Get creds */
	return nfs_req_creds(req);
}
Example #3
0
/**
 * @brief Get numeric credentials from request
 *
 * @todo This MUST be refactored to not use TI-RPC private structures.
 * Instead, export appropriate functions from lib(n)tirpc.
 *
 * fills out creds in op_ctx
 *
 * @param[in]  req              Incoming request.
 *
 * @return NFS4_OK if successful, NFS4ERR_ACCESS otherwise.
 *
 */
nfsstat4 nfs_req_creds(struct svc_req *req)
{
	unsigned int i;
	const char *auth_label = "UNKNOWN";
	gid_t **garray_copy = &op_ctx->caller_garray_copy;
#ifdef _HAVE_GSSAPI
	struct svc_rpc_gss_data *gd = NULL;
	char principal[MAXNAMLEN + 1];
#endif

	/* Make sure we clear out all the cred_flags except CREDS_LOADED and
	 * CREDS_ANON.
	 */
	op_ctx->cred_flags &= CREDS_LOADED | CREDS_ANON;

	switch (req->rq_cred.oa_flavor) {
	case AUTH_NONE:
		/* Nothing to be done here... */
		op_ctx->cred_flags |= CREDS_LOADED | CREDS_ANON;
		auth_label = "AUTH_NONE";
		break;

	case AUTH_SYS:
		if ((op_ctx->cred_flags & CREDS_LOADED) == 0) {
			struct authunix_parms *creds = NULL;

			/* We map the rq_cred to Authunix_parms */
			creds = (struct authunix_parms *) req->rq_clntcred;
			op_ctx->original_creds.caller_uid = creds->aup_uid;
			op_ctx->original_creds.caller_gid = creds->aup_gid;
			op_ctx->original_creds.caller_glen = creds->aup_len;
			op_ctx->original_creds.caller_garray = creds->aup_gids;
			op_ctx->cred_flags |= CREDS_LOADED;
		}

		/* Copy original_creds creds */
		*op_ctx->creds = op_ctx->original_creds;

		/* Do we trust AUTH_SYS creds for groups or not ? */
		if ((op_ctx->export_perms->options & EXPORT_OPTION_MANAGE_GIDS)
		    != 0) {
			op_ctx->cred_flags |= MANAGED_GIDS;
			garray_copy = &op_ctx->managed_garray_copy;
		}

		auth_label = "AUTH_SYS";
		break;

#ifdef _HAVE_GSSAPI
	case RPCSEC_GSS:
		if ((op_ctx->cred_flags & CREDS_LOADED) == 0) {
			/* Get the gss data to process them */
			gd = SVCAUTH_PRIVATE(req->rq_auth);

			memcpy(principal, gd->cname.value, gd->cname.length);
			principal[gd->cname.length] = 0;

			LogMidDebug(COMPONENT_DISPATCH,
				     "Mapping RPCSEC_GSS principal %s to uid/gid",
				     principal);

			/* Convert to uid */
#if _MSPAC_SUPPORT
			if (!principal2uid(principal,
					   &op_ctx->original_creds.caller_uid,
					   &op_ctx->original_creds.caller_gid,
					   gd)) {
#else
			if (!principal2uid(principal,
					   &op_ctx->original_creds.caller_uid,
					   &op_ctx->original_creds.caller_gid)
			   ) {
#endif
				LogWarn(COMPONENT_IDMAPPER,
					"Could not map principal %s to uid",
					principal);
				/* For compatibility with Linux knfsd, we set
				 * the uid/gid to anonymous when a name->uid
				 * mapping can't be found.
				 */
				op_ctx->cred_flags |= CREDS_ANON |
						       CREDS_LOADED;
				auth_label = "RPCSEC_GSS (no mapping)";
				break;
			}

			op_ctx->cred_flags |= CREDS_LOADED;
		}

		auth_label = "RPCSEC_GSS";
		op_ctx->cred_flags |= MANAGED_GIDS;
		garray_copy = &op_ctx->managed_garray_copy;

		break;
#endif				/* _USE_GSSRPC */

	default:
		LogMidDebug(COMPONENT_DISPATCH,
			     "FAILURE: Request xid=%u, has unsupported authentication %d",
			     req->rq_xid, req->rq_cred.oa_flavor);
		/* Reject the request for weak authentication and
		 * return to worker
		 */
		return NFS4ERR_ACCESS;

		break;
	}

	/****************************************************************/
	/* Now check for anon creds or id squashing			*/
	/****************************************************************/
	if ((op_ctx->cred_flags & CREDS_ANON) != 0 ||
	    ((op_ctx->export_perms->options &
	      EXPORT_OPTION_ALL_ANONYMOUS) != 0) ||
	    ((op_ctx->export_perms->options & EXPORT_OPTION_ROOT) == 0 &&
	      op_ctx->original_creds.caller_uid == 0)) {
		op_ctx->creds->caller_uid =
					op_ctx->export_perms->anonymous_uid;
		op_ctx->creds->caller_gid =
					op_ctx->export_perms->anonymous_gid;
		op_ctx->creds->caller_glen = 0;
		LogMidDebugAlt(COMPONENT_DISPATCH, COMPONENT_EXPORT,
			    "%s creds squashed to uid=%u, gid=%u",
			    auth_label,
			    op_ctx->creds->caller_uid,
			    op_ctx->creds->caller_gid);
		op_ctx->cred_flags |= UID_SQUASHED | GID_SQUASHED;
		return NFS4_OK;
	}

	/* Now we will use the original_creds uid from original credential */
	op_ctx->creds->caller_uid = op_ctx->original_creds.caller_uid;

	/****************************************************************/
	/* Now sqush group or use original_creds gid			*/
	/****************************************************************/
	if ((op_ctx->export_perms->options & EXPORT_OPTION_ROOT) == 0 &&
	    op_ctx->original_creds.caller_gid == 0) {
		/* Squash gid */
		op_ctx->creds->caller_gid =
					op_ctx->export_perms->anonymous_gid;
		op_ctx->cred_flags |= GID_SQUASHED;
	} else {
		/* Use original_creds gid */
		op_ctx->creds->caller_gid = op_ctx->original_creds.caller_gid;
	}

	/****************************************************************/
	/* Check if we have manage_gids.				*/
	/****************************************************************/
	if ((op_ctx->cred_flags & MANAGED_GIDS) != 0) {
		/* Fetch the group data if required */
		if (op_ctx->caller_gdata == NULL &&
		    !uid2grp(op_ctx->original_creds.caller_uid,
			     &op_ctx->caller_gdata)) {
			/** @todo: do we really want to bail here? */
			LogCrit(COMPONENT_DISPATCH,
				"Attempt to fetch managed_gids failed");
			return NFS4ERR_ACCESS;
		}

		op_ctx->creds->caller_glen = op_ctx->caller_gdata->nbgroups;
		op_ctx->creds->caller_garray = op_ctx->caller_gdata->groups;
	} else {
		/* Use the original_creds group list */
		op_ctx->creds->caller_glen   =
					op_ctx->original_creds.caller_glen;
		op_ctx->creds->caller_garray =
					op_ctx->original_creds.caller_garray;
	}

	/****************************************************************/
	/* Check the garray for gid 0 to squash				*/
	/****************************************************************/

	/* If no root squashing in caller_garray, return now */
	if ((op_ctx->export_perms->options & EXPORT_OPTION_ROOT) != 0 ||
	    op_ctx->creds->caller_glen == 0)
		goto out;

	for (i = 0; i < op_ctx->creds->caller_glen; i++) {
		if (op_ctx->creds->caller_garray[i] == 0) {
			/* Meed to make a copy, or use the old copy */
			if ((*garray_copy) == NULL) {
				/* Make a copy of the active garray */
				(*garray_copy) =
					gsh_malloc(op_ctx->creds->caller_glen *
						   sizeof(gid_t));

				memcpy((*garray_copy),
				       op_ctx->creds->caller_garray,
				       op_ctx->creds->caller_glen *
				       sizeof(gid_t));
			}

			/* Now squash the root id. Since the original copy is
			 * always the same, any root ids in it were still in
			 * the same place, so even if using a copy that had a
			 * different anonymous_gid, we're fine.
			 */
			(*garray_copy)[i] =
					op_ctx->export_perms->anonymous_gid;

			/* Indicate we squashed the caller_garray */
			op_ctx->cred_flags |= GARRAY_SQUASHED;
		}
	}

	/* If we squashed the caller_garray, use the squashed copy */
	if ((op_ctx->cred_flags & GARRAY_SQUASHED) != 0)
		op_ctx->creds->caller_garray = *garray_copy;

out:

	LogMidDebugAlt(COMPONENT_DISPATCH, COMPONENT_EXPORT,
		    "%s creds mapped to uid=%u, gid=%u%s, glen=%d%s",
		    auth_label,
		    op_ctx->creds->caller_uid,
		    op_ctx->creds->caller_gid,
		    (op_ctx->cred_flags & GID_SQUASHED) != 0
			? " (squashed)"
			: "",
		    op_ctx->creds->caller_glen,
		    (op_ctx->cred_flags & MANAGED_GIDS) != 0
			? ((op_ctx->cred_flags & GARRAY_SQUASHED) != 0
				? " (managed and squashed)"
				: " (managed)")
			: ((op_ctx->cred_flags & GARRAY_SQUASHED) != 0
				? " (squashed)"
				: ""));

	return NFS4_OK;
}

/**
 * @brief Initialize request context and credentials.
 *
 */
void init_credentials(void)
{
	memset(op_ctx->creds, 0, sizeof(*op_ctx->creds));
	memset(&op_ctx->original_creds, 0, sizeof(op_ctx->original_creds));
	op_ctx->creds->caller_uid = op_ctx->export_perms->anonymous_uid;
	op_ctx->creds->caller_gid = op_ctx->export_perms->anonymous_gid;
	op_ctx->caller_gdata = NULL;
	op_ctx->caller_garray_copy = NULL;
	op_ctx->managed_garray_copy = NULL;
	op_ctx->cred_flags = 0;
}