/* * Copyright (c) 1997,1999 The University of Utah and the Flux Group. * All rights reserved. * * Contributed by the Computer Security Research division, * INFOSEC Research and Technology Office, NSA. * * This file is part of the Flux OSKit. The OSKit is free software, also known * as "open source;" you can redistribute it and/or modify it under the terms * of the GNU General Public License (GPL), version 2, as published by the Free * Software Foundation (FSF). To explore alternate licensing terms, contact * the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271. * * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have * received a copy of the GPL along with the OSKit; see the file COPYING. If * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA. */ #include "sfs.h" #include static struct oskit_filesystem_ops fs_ops; static struct oskit_comsid_ops sid_ops; static struct oskit_filesystem_secure_ops sfs_ops; oskit_error_t sfilesystem_create(oskit_dir_t * root, oskit_security_id_t sid, oskit_services_t * osenv, oskit_filepsid_t * psid, oskit_avc_t * avc, oskit_security_t * security, struct sfilesystem ** out_sfs) { oskit_osenv_log_t *log; oskit_osenv_mem_t *mem; struct sfilesystem *sfs; oskit_services_lookup_first(osenv, &oskit_osenv_log_iid, (void **) &log); if (!log) return OSKIT_EINVAL; oskit_services_lookup_first(osenv, &oskit_osenv_mem_iid, (void **) &mem); if (!mem) return OSKIT_EINVAL; sfs = oskit_osenv_mem_alloc(mem, sizeof(struct sfilesystem), 0, 0); if (!sfs) return OSKIT_ENOMEM; sfs->fsi.ops = &fs_ops; sfs->sidi.ops = &sid_ops; sfs->sfsi.ops = &sfs_ops; sfs->count = 1; sfs->sid = sid; sfs->mem = mem; oskit_osenv_mem_addref(mem); sfs->log = log; oskit_osenv_log_addref(log); sfs->psid = psid; oskit_filepsid_addref(psid); sfs->avc = avc; oskit_avc_addref(avc); sfs->security = security; oskit_security_addref(security); sfs->root = root; oskit_dir_addref(root); sfs->fs = NULL; oskit_dir_getfs(root, &sfs->fs); sfs->ino2sf = hashtab_create(mem); if (!sfs->ino2sf) { if (sfs->fs) oskit_filesystem_release(sfs->fs); oskit_dir_release(root); oskit_security_release(security); oskit_avc_release(avc); oskit_filepsid_release(psid); oskit_osenv_log_release(log); oskit_osenv_mem_free(mem, sfs, 0, sizeof(struct sfilesystem)); oskit_osenv_mem_release(mem); return OSKIT_ENOMEM; } *out_sfs = sfs; return 0; } /* * oskit_filesystem methods */ static OSKIT_COMDECL filesystem_query(oskit_filesystem_t * f, const struct oskit_guid * iid, void **out_ihandle) { struct sfilesystem *sfs; sfs = (struct sfilesystem *) f; if (memcmp(iid, &oskit_iunknown_iid, sizeof(*iid)) == 0 || memcmp(iid, &oskit_filesystem_iid, sizeof(*iid)) == 0) { *out_ihandle = &sfs->fsi; ++sfs->count; return 0; } if (memcmp(iid, &oskit_comsid_iid, sizeof(*iid)) == 0) { *out_ihandle = &sfs->sidi; ++sfs->count; return 0; } *out_ihandle = NULL; return OSKIT_E_NOINTERFACE; } static OSKIT_COMDECL_U filesystem_addref(oskit_filesystem_t * f) { struct sfilesystem *sfs; sfs = (struct sfilesystem *) f; return ++sfs->count; } static OSKIT_COMDECL_U filesystem_release(oskit_filesystem_t * f) { struct sfilesystem *sfs; oskit_osenv_mem_t *mem; unsigned newcount; sfs = (struct sfilesystem *) f; newcount = --sfs->count; if (newcount == 0) { if (sfs->fs) oskit_filesystem_release(sfs->fs); oskit_dir_release(sfs->root); oskit_security_release(sfs->security); oskit_avc_release(sfs->avc); oskit_filepsid_release(sfs->psid); oskit_osenv_log_release(sfs->log); hashtab_destroy(sfs->ino2sf); mem = sfs->mem; oskit_osenv_mem_free(mem, sfs, 0, sizeof(struct sfilesystem)); oskit_osenv_mem_release(mem); } return newcount; } static OSKIT_COMDECL filesystem_statfs(oskit_filesystem_t * f, oskit_statfs_t * out_stats) { struct sfilesystem *sfs = (struct sfilesystem *) f; oskit_security_id_t csid; oskit_error_t rc; if (!sfs || !sfs->count || !sfs->fs) return OSKIT_E_INVALIDARG; CSID(&csid); rc = SFS_FS_HAS_PERM(csid, sfs, GETATTR); if (rc) return rc; return oskit_filesystem_statfs(sfs->fs, out_stats); } static OSKIT_COMDECL filesystem_sync(oskit_filesystem_t * f, oskit_bool_t wait) { struct sfilesystem *sfs = (struct sfilesystem *) f; if (!sfs || !sfs->count || !sfs->fs) return OSKIT_E_INVALIDARG; return oskit_filesystem_sync(sfs->fs, wait); } static OSKIT_COMDECL filesystem_getroot(oskit_filesystem_t * f, struct oskit_dir ** out_dir) { struct sfilesystem *sfs = (struct sfilesystem *) f; struct sfiledir *sdir; oskit_error_t rc; if (!sfs || !sfs->count || !sfs->fs) return OSKIT_E_INVALIDARG; rc = sfiledir_create(sfs, (oskit_file_t *) sfs->root, &sdir); if (rc) return rc; *out_dir = (oskit_dir_t *) & sdir->filei; return 0; } static OSKIT_COMDECL filesystem_remount(oskit_filesystem_t * f, oskit_u32_t flags) { struct sfilesystem *sfs = (struct sfilesystem *) f; oskit_security_id_t csid; oskit_error_t rc; if (!sfs || !sfs->count || !sfs->fs) return OSKIT_E_INVALIDARG; CSID(&csid); rc = SFS_FS_HAS_PERM(csid, sfs, REMOUNT); if (rc) return rc; return oskit_filesystem_remount(sfs->fs, flags); } static OSKIT_COMDECL filesystem_unmount(oskit_filesystem_t * f) { struct sfilesystem *sfs = (struct sfilesystem *) f; oskit_security_id_t csid; oskit_error_t rc; if (!sfs || !sfs->count || !sfs->fs) return OSKIT_E_INVALIDARG; CSID(&csid); rc = SFS_FS_HAS_PERM(csid, sfs, UNMOUNT); if (rc) return rc; return oskit_filesystem_unmount(sfs->fs); } static OSKIT_COMDECL filesystem_lookupi(oskit_filesystem_t * f, oskit_ino_t ino, oskit_file_t ** out_file) { struct sfilesystem *sfs = (struct sfilesystem *) f; oskit_security_id_t csid; oskit_error_t rc; if (!sfs || !sfs->count || !sfs->fs) return OSKIT_E_INVALIDARG; CSID(&csid); rc = SFS_FS_HAS_PERM(csid, sfs, LOOKUPI); if (rc) return rc; return oskit_filesystem_lookupi(sfs->fs,ino,out_file); } static struct oskit_filesystem_ops fs_ops = { filesystem_query, filesystem_addref, filesystem_release, filesystem_statfs, filesystem_sync, filesystem_getroot, filesystem_remount, filesystem_unmount, filesystem_lookupi, }; /* * oskit_comsid methods */ static OSKIT_COMDECL sid_query(oskit_comsid_t * s, const struct oskit_guid * iid, void **out_ihandle) { struct sfilesystem *sfs; sfs = (struct sfilesystem *) ((char *) s - offsetof(struct sfilesystem, sidi)); return oskit_filesystem_query(&sfs->fsi, iid, out_ihandle); } static OSKIT_COMDECL_U sid_addref(oskit_comsid_t * s) { struct sfilesystem *sfs; sfs = (struct sfilesystem *) ((char *) s - offsetof(struct sfilesystem, sidi)); return oskit_filesystem_addref(&sfs->fsi); } static OSKIT_COMDECL_U sid_release(oskit_comsid_t * s) { struct sfilesystem *sfs; sfs = (struct sfilesystem *) ((char *) s - offsetof(struct sfilesystem, sidi)); return oskit_filesystem_release(&sfs->fsi); } static OSKIT_COMDECL sid_get(oskit_comsid_t * s, oskit_security_class_t * outclass, oskit_security_id_t * outsid) { struct sfilesystem *sfs; sfs = (struct sfilesystem *) ((char *) s - offsetof(struct sfilesystem, sidi)); *outclass = OSKIT_SECCLASS_FILESYSTEM; *outsid = sfs->sid; return 0; } static OSKIT_COMDECL sid_set(oskit_comsid_t * s, oskit_security_id_t newsid) { struct sfilesystem *sfs; sfs = (struct sfilesystem *) ((char *) s - offsetof(struct sfilesystem, sidi)); return oskit_filepsid_setfs(sfs->psid, newsid, OSKIT_SECSID_NULL); } static struct oskit_comsid_ops sid_ops = { sid_query, sid_addref, sid_release, sid_get, sid_set }; /* * oskit_filesystem_secure methods */ static OSKIT_COMDECL sfs_query(oskit_filesystem_secure_t * s, const struct oskit_guid * iid, void **out_ihandle) { struct sfilesystem *sfs; sfs = (struct sfilesystem *) ((char *) s - offsetof(struct sfilesystem, sfsi)); return oskit_filesystem_query(&sfs->fsi, iid, out_ihandle); } static OSKIT_COMDECL_U sfs_addref(oskit_filesystem_secure_t * s) { struct sfilesystem *sfs; sfs = (struct sfilesystem *) ((char *) s - offsetof(struct sfilesystem, sfsi)); return oskit_filesystem_addref(&sfs->fsi); } static OSKIT_COMDECL_U sfs_release(oskit_filesystem_secure_t * s) { struct sfilesystem *sfs; sfs = (struct sfilesystem *) ((char *) s - offsetof(struct sfilesystem, sfsi)); return oskit_filesystem_release(&sfs->fsi); } static OSKIT_COMDECL sfs_chsidfs(oskit_filesystem_secure_t * s, oskit_security_id_t fs_sid, oskit_security_id_t f_sid) { struct sfilesystem *sfs; oskit_security_id_t csid; oskit_error_t rc; sfs = (struct sfilesystem *) ((char *) s - offsetof(struct sfilesystem, sfsi)); if (!sfs || !sfs->count || !sfs->fs) return OSKIT_E_INVALIDARG; CSID(&csid); rc = SFS_FS_HAS_PERM(csid, sfs, RELABELFROM); if (rc) return rc; rc = oskit_avc_has_perm(sfs->avc, sfs->sid, fs_sid, OSKIT_SECCLASS_FILESYSTEM, OSKIT_PERM_FILESYSTEM__TRANSITION); if (rc) return rc; rc = oskit_avc_has_perm(sfs->avc, csid, fs_sid, OSKIT_SECCLASS_FILESYSTEM, OSKIT_PERM_FILESYSTEM__RELABELTO); if (rc) return rc; rc = oskit_avc_has_perm(sfs->avc, f_sid, fs_sid, OSKIT_SECCLASS_FILESYSTEM, OSKIT_PERM_FILESYSTEM__ASSOCIATE); if (rc) return rc; rc = oskit_filepsid_setfs(sfs->psid, fs_sid, f_sid); if (rc) return rc; sfs->sid = fs_sid; return 0; } static struct oskit_filesystem_secure_ops sfs_ops = { sfs_query, sfs_addref, sfs_release, sfs_chsidfs };