From 97ab15cc9eadc1aab563b87a0c92d559cd9e9a41 Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Wed, 29 Oct 2008 11:49:38 +0200 Subject: [PATCH] Add fsm and rpmfi machinery for file capabilities - new rpmfiFCaps() API to retrieve the info from rpmfi set - fsm internals quite similar to selinux handling - plenty of #ifdef's, another possibility would be adding cap_foo dummies to system.h like for selinux --- lib/cpio.c | 1 + lib/cpio.h | 3 ++- lib/fsm.c | 35 +++++++++++++++++++++++++++++++++++ lib/fsm.h | 2 ++ lib/rpmfi.c | 12 ++++++++++++ lib/rpmfi.h | 9 +++++++++ lib/rpmfi_internal.h | 2 ++ system.h | 2 ++ 8 files changed, 65 insertions(+), 1 deletion(-) diff --git a/lib/cpio.c b/lib/cpio.c index f45644b21..d4265d3b7 100644 --- a/lib/cpio.c +++ b/lib/cpio.c @@ -209,6 +209,7 @@ const char * cpioStrerror(int rc) case CPIOERR_READ_FAILED: s = "read"; break; case CPIOERR_COPY_FAILED: s = "copy"; break; case CPIOERR_LSETFCON_FAILED: s = "lsetfilecon"; break; + case CPIOERR_SETCAP_FAILED: s = "cap_set_file"; break; case CPIOERR_HDR_SIZE: s = _("Header size too big"); break; case CPIOERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break; diff --git a/lib/cpio.h b/lib/cpio.h index 5259b0325..fc6e92c61 100644 --- a/lib/cpio.h +++ b/lib/cpio.h @@ -52,7 +52,8 @@ enum cpioErrorReturns { CPIOERR_INTERNAL = (28 ), CPIOERR_UNMAPPED_FILE = (29 ), CPIOERR_ENOENT = (30 ), - CPIOERR_ENOTEMPTY = (31 ) + CPIOERR_ENOTEMPTY = (31 ), + CPIOERR_SETCAP_FAILED = (32 | CPIOERR_CHECK_ERRNO), }; /* diff --git a/lib/fsm.c b/lib/fsm.c index 8175f825f..ecfb1f703 100644 --- a/lib/fsm.c +++ b/lib/fsm.c @@ -589,6 +589,22 @@ static int fsmMapFContext(FSM_t fsm) return 0; } +#if WITH_CAP +static int fsmMapFCaps(FSM_t fsm) +{ + rpmts ts = fsmGetTs(fsm); + rpmfi fi = fsmGetFi(fsm); + fsm->fcaps = NULL; + if (ts != NULL && fi->fcaps && *fi->fcaps[fsm->ix] != '\0') { + cap_t fcaps = cap_from_text(fi->fcaps[fsm->ix]); + if (fcaps) { + fsm->fcaps = fcaps; + } + } + return 0; +} +#endif + /** * Map next file path and action. * @param fsm file state machine @@ -1869,6 +1885,16 @@ if (!(fsm->mapFlags & CPIO_ALL_HARDLINKS)) break; rc = fsmNext(fsm, FSM_UTIME); st->st_mtime = mtime; } +#if WITH_CAP + if (!rc && !S_ISDIR(st->st_mode) && !getuid()) { + rc = fsmMapFCaps(fsm); + if (!rc && fsm->fcaps) { + rc = fsmNext(fsm, FSM_SETCAP); + cap_free(fsm->fcaps); + } + fsm->fcaps = NULL; + } +#endif /* WITH_CAP */ } } @@ -2077,6 +2103,14 @@ if (!(fsm->mapFlags & CPIO_ALL_HARDLINKS)) break; if (rc < 0) rc = CPIOERR_UTIME_FAILED; } break; +#if WITH_CAP + case FSM_SETCAP: + rc = cap_set_file(fsm->path, fsm->fcaps); + if (rc < 0) { + rc = CPIOERR_SETCAP_FAILED; + } + break; +#endif /* WITH_CAP */ case FSM_SYMLINK: rc = symlink(fsm->opath, fsm->path); if (_fsm_debug && (stage & FSM_SYSCALL)) @@ -2357,6 +2391,7 @@ static const char * fileStageString(fileStage a) { case FSM_STAT: return "stat"; case FSM_READLINK: return "readlink"; case FSM_CHROOT: return "chroot"; + case FSM_SETCAP: return "setcap"; case FSM_NEXT: return "next"; case FSM_EAT: return "eat"; diff --git a/lib/fsm.h b/lib/fsm.h index 94fb8c3fd..89bc750a2 100644 --- a/lib/fsm.h +++ b/lib/fsm.h @@ -64,6 +64,7 @@ typedef enum fileStage_e { FSM_STAT = _fs(49), FSM_READLINK= _fs(50), FSM_CHROOT = _fs(51), + FSM_SETCAP = _fs(52), FSM_NEXT = _fd(65), FSM_EAT = _fd(66), @@ -154,6 +155,7 @@ struct fsm_s { const char * baseName; /*!< File base name. */ const char * digest; /*!< Binary checksum (NULL disables). */ security_context_t fcontext;/*!< File security context (NULL disables). */ + cap_t fcaps; /*!< File capabilities */ pgpHashAlgo digestalgo; /*!< File checksum algorithm */ unsigned fflags; /*!< File flags. */ diff --git a/lib/rpmfi.c b/lib/rpmfi.c index dfa15c318..bf037612c 100644 --- a/lib/rpmfi.c +++ b/lib/rpmfi.c @@ -371,6 +371,15 @@ const char * rpmfiFGroup(rpmfi fi) return fgroup; } +const char * rpmfiFCaps(rpmfi fi) +{ + const char *fcaps = NULL; + if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) { + fcaps = fi->fcaps ? fi->fcaps[fi->i] : ""; + } + return fcaps; +} + int rpmfiNext(rpmfi fi) { int i = -1; @@ -1124,6 +1133,7 @@ fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, fi->Type, fi->fc); fi->flinks = _free(fi->flinks); fi->flangs = _free(fi->flangs); fi->digests = _free(fi->digests); + fi->fcaps = _free(fi->fcaps); fi->cdict = _free(fi->cdict); @@ -1261,6 +1271,8 @@ rpmfi rpmfiNew(const rpmts ts, Header h, rpmTag tagN, int scareMem) if (fi->fstates == NULL) fi->fstates = xcalloc(fi->fc, sizeof(*fi->fstates)); + _hgfi(h, RPMTAG_FILECAPS, &td, defFlags, fi->fcaps); + fi->action = FA_UNKNOWN; fi->flags = 0; diff --git a/lib/rpmfi.h b/lib/rpmfi.h index a96f627ae..f3498f643 100644 --- a/lib/rpmfi.h +++ b/lib/rpmfi.h @@ -327,6 +327,15 @@ const char * rpmfiFUser(rpmfi fi); */ const char * rpmfiFGroup(rpmfi fi); +/** \ingroup rpmfi + * Return textual representation of current file capabilities + * from file info set. See cap_from_text(3) for details. + * @param fi file info set + * @return file capability description, "" for no capabilities + * and NULL on invalid + */ +const char * rpmfiFCaps(rpmfi fi); + /** \ingroup rpmfi * Return next file iterator index. * @param fi file info set diff --git a/lib/rpmfi_internal.h b/lib/rpmfi_internal.h index c913a20e5..4e0180eb0 100644 --- a/lib/rpmfi_internal.h +++ b/lib/rpmfi_internal.h @@ -61,6 +61,8 @@ struct rpmfi_s { const char ** fcontexts; /*! FIle security contexts. */ + const char ** fcaps; /*! File capabilities (header) */ + const char ** cdict; /*!< File class dictionary (header) */ rpm_count_t ncdict; /*!< No. of class entries. */ const uint32_t * fcdictx; /*!< File class dictionary index (header) */ diff --git a/system.h b/system.h index 3818e12dd..8c2f8150f 100644 --- a/system.h +++ b/system.h @@ -229,6 +229,8 @@ void * _free(void * p) #if WITH_CAP #include +#else +typedef void * cap_t; #endif #if WITH_ACL