Index: lib/libcasper/services/cap_fileargs/cap_fileargs.h =================================================================== --- lib/libcasper/services/cap_fileargs/cap_fileargs.h +++ lib/libcasper/services/cap_fileargs/cap_fileargs.h @@ -39,6 +39,7 @@ #ifdef WITH_CASPER struct fileargs; typedef struct fileargs fileargs_t; +struct stat; fileargs_t *fileargs_init(int argc, char *argv[], int flags, mode_t mode, cap_rights_t *rightsp); @@ -46,6 +47,7 @@ int flags, mode_t mode, cap_rights_t *rightsp); fileargs_t *fileargs_initnv(nvlist_t *limits); fileargs_t *fileargs_cinitnv(cap_channel_t *cas, nvlist_t *limits); +int fileargs_lstat(fileargs_t *fa, const char *name, struct stat *sb); int fileargs_open(fileargs_t *fa, const char *name); void fileargs_free(fileargs_t *fa); FILE *fileargs_fopen(fileargs_t *fa, const char *name, const char *mode); Index: lib/libcasper/services/cap_fileargs/cap_fileargs.3 =================================================================== --- lib/libcasper/services/cap_fileargs/cap_fileargs.3 +++ lib/libcasper/services/cap_fileargs/cap_fileargs.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 12, 2018 +.Dd March 12, 2019 .Dt CAP_FILEARGS 3 .Os .Sh NAME @@ -33,6 +33,7 @@ .Nm fileargs_init , .Nm fileargs_initnv , .Nm fileargs_free , +.Nm fileargs_lstat , .Nm fileargs_open , .Nm fileargs_fopen .Nd "library for handling files in capability mode" @@ -53,6 +54,8 @@ .Ft "void" .Fn fileargs_free "fileargs_t *fa" .Ft "int" +.Fn fileargs_lstat "fileargs_t *fa" "const char *path" "struct stat *sb" +.Ft "int" .Fn fileargs_open "fileargs_t *fa" "const char *name" .Ft "FILE *" .Fn fileargs_fopen "fileargs_t *fa" "const char *name" "const char *mode" @@ -126,6 +129,11 @@ .Dv NULL argument. .Pp +The function +.Fn fileargs_lstat +is equivalent to +.Xr lstat 2 . +.Pp The functions .Fn fileargs_open and @@ -222,6 +230,7 @@ .Ed .Sh SEE ALSO .Xr cap_enter 2 , +.Xr lstat 2 , .Xr open 2 , .Xr cap_rights_init 3 , .Xr err 3 , Index: lib/libcasper/services/cap_fileargs/cap_fileargs.c =================================================================== --- lib/libcasper/services/cap_fileargs/cap_fileargs.c +++ lib/libcasper/services/cap_fileargs/cap_fileargs.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -59,7 +60,42 @@ }; static int -fileargs_get_cache(fileargs_t *fa, const char *name) +fileargs_get_lstat_cache(fileargs_t *fa, const char *name, struct stat *sb) +{ + const nvlist_t *nvl; + nvlist_t *tnvl; + size_t size; + const void *buf; + + assert(fa != NULL); + assert(fa->fa_magic == FILEARGS_MAGIC); + assert(name != NULL); + + if (fa->fa_cache == NULL) + return (-1); + + nvl = dnvlist_get_nvlist(fa->fa_cache, name, NULL); + if (nvl == NULL) + return (-1); + + tnvl = nvlist_take_nvlist(fa->fa_cache, name); + + if (!nvlist_exists_binary(tnvl, "stat")) { + nvlist_destroy(tnvl); + return (-1); + } + + buf = nvlist_get_binary(tnvl, "stat", &size); + assert(size == sizeof(*sb)); + memcpy(sb, buf, size); + + nvlist_destroy(tnvl); + + return (0); +} + +static int +fileargs_get_fd_cache(fileargs_t *fa, const char *name) { int fd; const nvlist_t *nvl; @@ -80,6 +116,12 @@ return (-1); tnvl = nvlist_take_nvlist(fa->fa_cache, name); + + if (!nvlist_exists_descriptor(tnvl, "fd")) { + nvlist_destroy(tnvl); + return (-1); + } + fd = nvlist_take_descriptor(tnvl, "fd"); nvlist_destroy(tnvl); @@ -102,7 +144,7 @@ } static nvlist_t* -fileargs_fetch(fileargs_t *fa, const char *name) +fileargs_fetch(fileargs_t *fa, const char *name, const char *cmd) { nvlist_t *nvl; int serrno; @@ -111,7 +153,7 @@ assert(name != NULL); nvl = nvlist_create(NV_FLAG_NO_UNIQUE); - nvlist_add_string(nvl, "cmd", "open"); + nvlist_add_string(nvl, "cmd", cmd); nvlist_add_string(nvl, "name", name); nvl = cap_xfer_nvlist(fa->fa_chann, nvl); @@ -291,11 +333,11 @@ return (-1); } - fd = fileargs_get_cache(fa, name); + fd = fileargs_get_fd_cache(fa, name); if (fd != -1) return (fd); - nvl = fileargs_fetch(fa, name); + nvl = fileargs_fetch(fa, name, "open"); if (nvl == NULL) return (-1); @@ -322,6 +364,53 @@ return (fdopen(fd, mode)); } +int +fileargs_lstat(fileargs_t *fa, const char *name, struct stat *sb) +{ + nvlist_t *nvl; + char *cmd; + const void *buf; + size_t size; + + assert(fa != NULL); + assert(fa->fa_magic == FILEARGS_MAGIC); + + if (name == NULL) { + errno = EINVAL; + return (-1); + } + + if (sb == NULL) { + errno = EFAULT; + return (-1); + } + + if (fa->fa_chann == NULL) { + errno = ENOTCAPABLE; + return (-1); + } + + if (fileargs_get_lstat_cache(fa, name, sb) != -1) + return (0); + + nvl = fileargs_fetch(fa, name, "lstat"); + if (nvl == NULL) + return (-1); + + buf = nvlist_get_binary(nvl, "stat", &size); + assert(size == sizeof(*sb)); + memcpy(sb, buf, size); + cmd = nvlist_take_string(nvl, "cmd"); + + if (strcmp(cmd, "cache") == 0) + fileargs_set_cache(fa, nvl); + else + nvlist_destroy(nvl); + free(cmd); + + return (0); +} + void fileargs_free(fileargs_t *fa) { @@ -375,7 +464,51 @@ } static void -fileargs_add_cache(nvlist_t *nvlout, const nvlist_t *limits, +fileargs_add_lstat_cache(nvlist_t *nvlout, const nvlist_t *limits, + const char *curent_name) +{ + int type, i; + void *cookie; + nvlist_t *new; + const char *fname; + struct stat sb; + + cookie = cacheposition; + for (i = 0; i < CACHE_SIZE + 1; i++) { + fname = nvlist_next(limits, &type, &cookie); + if (fname == NULL) { + cacheposition = NULL; + lastname = NULL; + allcached = true; + return; + } + /* We doing that to catch next element name. */ + if (i == CACHE_SIZE) { + break; + } + + if (type != NV_TYPE_NULL || + (curent_name != NULL && strcmp(fname, curent_name) == 0)) { + curent_name = NULL; + i--; + continue; + } + + if (lstat(fname, &sb) < 0) { + i--; + continue; + } + + new = nvlist_create(NV_FLAG_NO_UNIQUE); + nvlist_add_binary(new, "stat", &sb, sizeof(sb)); + nvlist_add_nvlist(nvlout, fname, new); + } + cacheposition = cookie; + lastname = fname; +} + +static void +fileargs_add_fd_cache(nvlist_t *nvlout, const nvlist_t *limits, const char *curent_name) { int type, i, fd; @@ -460,6 +593,37 @@ return (0); } +static int +fileargs_command_lstat(const nvlist_t *limits, nvlist_t *nvlin, + nvlist_t *nvlout) +{ + int stat; + const char *name; + struct stat sb; + + if (limits == NULL) + return (ENOTCAPABLE); + + if (!fileargs_allowed(limits, nvlin)) + return (ENOTCAPABLE); + + name = nvlist_get_string(nvlin, "name"); + + stat = lstat(name, &sb); + if (stat < 0) + return (errno); + + if (!allcached && (lastname == NULL || + strcmp(name, lastname) == 0)) { + nvlist_add_string(nvlout, "cmd", "cache"); + fileargs_add_lstat_cache(nvlout, limits, name); + } else { + nvlist_add_string(nvlout, "cmd", "lstat"); + } + nvlist_add_binary(nvlout, "stat", &sb, sizeof(sb)); + return (0); +} + static int fileargs_command_open(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) @@ -482,7 +646,7 @@ if (!allcached && (lastname == NULL || strcmp(name, lastname) == 0)) { nvlist_add_string(nvlout, "cmd", "cache"); - fileargs_add_cache(nvlout, limits, name); + fileargs_add_fd_cache(nvlout, limits, name); } else { nvlist_add_string(nvlout, "cmd", "open"); } @@ -498,6 +662,9 @@ if (strcmp(cmd, "open") == 0) return (fileargs_command_open(limits, nvlin, nvlout)); + if (strcmp(cmd, "lstat") == 0) + return (fileargs_command_lstat(limits, nvlin, nvlout)); + return (EINVAL); }