[pacman-dev] [PATCH WIP] Allow pacman to be run as a non-root user
In order to run pacman as a non-root user to install packages to non-system (somewhere in $HOME or something) it was required to fake your root status using fakeroot. This allows users to specify a config directive, `NoRoot` to tell pacman that it should not check for root privileges. There is also an option in makepkg to allow it to not use root, as otherwise it will call 'sudo' or 'su' when using pacman to install or remove installed packages. --- WIP. I'm intending to use pacman and makepkg as a manager for some game mods, and this was the only thing really holding it back. I had done some tests using fakeroot and other ways of getting around these checks, but this is something that I thought should really go into pacman. Will allow even more people to use things like pacman and PKGBUILDs for other things, like games and user packages. Might also let us do some testing without having to fake root. Because WIP I haven't added docs yet. Just thought I'd get someone to look this over because I generally don't code in C, and it probably is disgusting. It's really just a carbon copy of the checkspace stuff, except in util.c. Thanks for looking it over, and sorry in advance for it being horrible. Bill Giokas (kaictl) lib/libalpm/alpm.h | 3 +++ lib/libalpm/handle.c | 13 +++++++++++++ lib/libalpm/handle.h | 1 + scripts/makepkg.sh.in | 10 ++++++---- src/pacman/conf.c | 3 +++ src/pacman/conf.h | 1 + src/pacman/util.c | 3 +++ 7 files changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index b0adb95..10d38bb 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -675,6 +675,9 @@ int alpm_option_set_deltaratio(alpm_handle_t *handle, double ratio); int alpm_option_get_checkspace(alpm_handle_t *handle); int alpm_option_set_checkspace(alpm_handle_t *handle, int checkspace); +int alpm_option_get_noroot(alpm_handle_t *handle); +int alpm_option_set_noroot(alpm_handle_t *handle, int noroot); + alpm_siglevel_t alpm_option_get_default_siglevel(alpm_handle_t *handle); int alpm_option_set_default_siglevel(alpm_handle_t *handle, alpm_siglevel_t level); diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index 0842d51..c9ad007 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -252,6 +252,12 @@ int SYMEXPORT alpm_option_get_checkspace(alpm_handle_t *handle) return handle->checkspace; } +int SYMEXPORT alpm_option_get_noroot(alpm_handle_t *handle) +{ + CHECK_HANDLE(handle, return -1); + return handle->noroot; +} + int SYMEXPORT alpm_option_set_dlcb(alpm_handle_t *handle, alpm_cb_download cb) { CHECK_HANDLE(handle, return -1); @@ -593,6 +599,13 @@ int SYMEXPORT alpm_option_set_checkspace(alpm_handle_t *handle, int checkspace) return 0; } +int SYMEXPORT alpm_option_set_noroot(alpm_handle_t *handle, int noroot) +{ + CHECK_HANDLE(handle, return -1); + handle->noroot = noroot; + return 0; +} + int SYMEXPORT alpm_option_set_default_siglevel(alpm_handle_t *handle, alpm_siglevel_t level) { diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index 27241ea..650fe27 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -89,6 +89,7 @@ struct __alpm_handle_t { double deltaratio; /* Download deltas if possible; a ratio value */ int usesyslog; /* Use syslog instead of logfile? */ /* TODO move to frontend */ int checkspace; /* Check disk space before installing */ + int noroot; /* Don't check for root status when running */ alpm_siglevel_t siglevel; /* Default signature verification level */ alpm_siglevel_t localfilesiglevel; /* Signature verification level for local file upgrade operations */ diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index e230c15..dda4644 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -77,6 +77,7 @@ NEEDED=0 NOBUILD=0 NODEPS=0 NOEXTRACT=0 +NOROOT=0 PKGFUNC=0 PKGLIST=() PKGVERFUNC=0 @@ -1005,7 +1006,7 @@ run_pacman() { else cmd=("$PACMAN_PATH" "$@") fi - if (( ! ASROOT )) && [[ ! $1 = -@(T|Qq) ]]; then + if (( ! ASROOT )) && [[ ! $1 = -@(T|Qq) ]] && (( ! $NOROOT )); then if type -p sudo >/dev/null; then cmd=(sudo "${cmd[@]}") else @@ -2584,9 +2585,9 @@ ARGLIST=("$@") OPT_SHORT="AcCdefFghiLmop:rRsSV" OPT_LONG=('allsource' 'asroot' 'check' 'clean' 'cleanbuild' 'config:' 'force' 'geninteg' 'help' 'holdver' 'ignorearch' 'install' 'key:' 'log' 'nobuild' 'nocolor' - 'nocheck' 'nodeps' 'noextract' 'noprepare' 'nosign' 'pkg:' 'repackage' 'rmdeps' - 'sign' 'skipchecksums' 'skipinteg' 'skippgpcheck' 'source' 'syncdeps' - 'verifysource' 'version') + 'nocheck' 'nodeps' 'noextract' 'noprepare' 'noroot' 'nosign' 'pkg:' + 'repackage' 'rmdeps' 'sign' 'skipchecksums' 'skipinteg' 'skippgpcheck' + 'source' 'syncdeps' 'verifysource' 'version') # Pacman Options OPT_LONG+=('asdeps' 'noconfirm' 'needed' 'noprogressbar') @@ -2601,6 +2602,7 @@ while true; do case "$1" in # Pacman Options --asdeps) ASDEPS=1;; + --noroot) NOROOT=1;; --noconfirm) PACMAN_OPTS+=" --noconfirm" ;; --needed) NEEDED=1;; --noprogressbar) PACMAN_OPTS+=" --noprogressbar" ;; diff --git a/src/pacman/conf.c b/src/pacman/conf.c index f75f3a7..5bea270 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -491,6 +491,8 @@ static int _parse_options(const char *key, char *value, pm_printf(ALPM_LOG_DEBUG, "config: totaldownload\n"); } else if(strcmp(key, "CheckSpace") == 0) { config->checkspace = 1; + } else if(strcmp(key, "NoRoot") == 0) { + config->noroot = 1; } else if(strcmp(key, "Color") == 0) { if(config->color == PM_COLOR_UNSET) { config->color = isatty(fileno(stdout)) ? PM_COLOR_ON : PM_COLOR_OFF; @@ -734,6 +736,7 @@ static int setup_libalpm(void) alpm_option_set_arch(handle, config->arch); alpm_option_set_checkspace(handle, config->checkspace); + alpm_option_set_noroot(handle, config->noroot); alpm_option_set_usesyslog(handle, config->usesyslog); alpm_option_set_deltaratio(handle, config->deltaratio); diff --git a/src/pacman/conf.h b/src/pacman/conf.h index e8cac50..a6a87a9 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -45,6 +45,7 @@ typedef struct __config_t { unsigned short logmask; unsigned short print; unsigned short checkspace; + unsigned short noroot; unsigned short usesyslog; unsigned short color; double deltaratio; diff --git a/src/pacman/util.c b/src/pacman/util.c index d42e27b..d10bc7d 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -102,6 +102,9 @@ int trans_release(void) int needs_root(void) { + if(config->noroot == 1) { + return 0; + } switch(config->op) { case PM_OP_DATABASE: return 1; -- 1.9.0
On 04/03/14 10:19, William Giokas wrote:
In order to run pacman as a non-root user to install packages to non-system (somewhere in $HOME or something) it was required to fake your root status using fakeroot. This allows users to specify a config directive, `NoRoot` to tell pacman that it should not check for root privileges.
There is also an option in makepkg to allow it to not use root, as otherwise it will call 'sudo' or 'su' when using pacman to install or remove installed packages. ---
WIP. I'm intending to use pacman and makepkg as a manager for some game mods, and this was the only thing really holding it back. I had done some tests using fakeroot and other ways of getting around these checks, but this is something that I thought should really go into pacman. Will allow even more people to use things like pacman and PKGBUILDs for other things, like games and user packages. Might also let us do some testing without having to fake root.
Because WIP I haven't added docs yet. Just thought I'd get someone to look this over because I generally don't code in C, and it probably is disgusting. It's really just a carbon copy of the checkspace stuff, except in util.c.
Thanks for looking it over, and sorry in advance for it being horrible.
Bill Giokas (kaictl)
<snip>
diff --git a/src/pacman/util.c b/src/pacman/util.c index d42e27b..d10bc7d 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -102,6 +102,9 @@ int trans_release(void)
int needs_root(void) { + if(config->noroot == 1) { + return 0; + } switch(config->op) { case PM_OP_DATABASE: return 1;
pacman -S --noroot glibc -> BOOM! Well, boom being pacman errors out during package extraction. At a minimum, I would expect pacman to check whether I can write to all the directories in the package file. The database directory should only ever be writeable by root. It would be a major security issue otherwise (particularly as one promenant distribution can still not sign databases...). So how would a user of "--noroot" add a database? If we are restricting them to -U, there is no need for makepkg support. In conclusion, I'd like to see a very well thought out plan discussed before I look at code for this. Allan
On Tue, Mar 04, 2014 at 01:38:17PM +1000, Allan McRae wrote:
<snip>
diff --git a/src/pacman/util.c b/src/pacman/util.c index d42e27b..d10bc7d 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -102,6 +102,9 @@ int trans_release(void)
int needs_root(void) { + if(config->noroot == 1) { + return 0; + } switch(config->op) { case PM_OP_DATABASE: return 1;
pacman -S --noroot glibc -> BOOM!
Well, boom being pacman errors out during package extraction. At a minimum, I would expect pacman to check whether I can write to all the directories in the package file.
Currently it's not doing any of that checking in order to make things somewhat simpler for me. I've barely written anything in C before, so this is basically me experimenting a little bit to get a POC. Another thing that could happen is just a check of the RootDir, DBPath... and others that pacman uses. This way --noroot would almost not even be needed, as simply setting RootDir and the other options to user-writeable paths would allow them to run this without issue. (Obviously it would still error out if it's unable to write to directories below that, though, but as root you won't have that problem and as a user you should keep a handle on that problem).
The database directory should only ever be writeable by root. It would be a major security issue otherwise (particularly as one promenant distribution can still not sign databases...). So how would a user of "--noroot" add a database? If we are restricting them to -U, there is no need for makepkg support.
It's a security issue if the database directory for a system is writeable by a non-root user, however the point of this is to allow makepkg and pacman to be used for non-system applications, similar to the way that pip can be used in a virtualenv. You would set RootDir to somewhere that you have write access to (/home/wgiokas/foo) and, get it set up for pacman (add the directories it needs) and then run it with --noroot. Pacman is going to error itself now if it can't write files.
In conclusion, I'd like to see a very well thought out plan discussed before I look at code for this.
Alright, I'll keep working on stuff. Thanks for the feedback, though. There's still a whole lot more that I've found that needs to be changed to use this to extract and work with packages as a non-root user. Thanks, -- William Giokas | KaiSforza | http://kaictl.net/ GnuPG Key: 0x73CD09CF Fingerprint: F73F 50EF BBE2 9846 8306 E6B8 6902 06D8 73CD 09CF
I was really happy to find this post today as I have wanted to use pacman for user package installs in the past and came back to this problem today. William, did you take this idea any further? I'll try to flesh out a use-case in case it helps. I am not an expert user of makepkg or pacman. I'm looking for a package manager to use on a multi-user system for user installable libraries and software. (eg the RootDir would be ~/.local, and the repo cache and database would be in the users /home path). Implicit is that the repo database is unique to that user (on an Archlinux system there would also be the normal system repo database). I have a large number of users, all developing a complex software. To partition and synchronize the work, the software is broken into a number of library and binary packages. The package manager (pacman for the purposes of the rest of the discussion) would speed and ease installation of (project specific) dependencies. Since version dependencies are handled by pacman, the build tools don't have to worry if the correct versions of each library are installed. Deployment to existing developers and setting up new developers is fast and deployment in the field is the same. Beyond the root user permissions issue that william tackled, there is the issue that we have two domains of dependencies (system and user). At some point the user repo will need to know that the system fulfills some of it's dependencies. Where I to grab williams patch and just start hacking, my approach would be to manually generate a set of dummy packages that are empty but 'provide' the system installed packages (an empty glibc package for instance). A pre-install script to verify that the package is actually installed at the system level would probably be desirable. I believe the above approach would work, letting the two package repos do their jobs. However it's labor intensive to fill in the interface layer of packages needed by the user repo. Having the user repo database cascade to the system repo database would be even better (first check for a dependency in the user repo database, and if it's not available there, check the system repo database. If in the system, dump the system package list to the terminal so the user can either install via sudo or send a request to the administrator.) Does that make sense? -Hauptmech
The database directory should only ever be writeable by root. It would be a major security issue otherwise (particularly as one promenant distribution can still not sign databases...). So how would a user of "--noroot" add a database? If we are restricting them to -U, there is no need for makepkg support. It's a security issue if the database directory for a system is writeable by a non-root user, however the point of this is to allow makepkg and pacman to be used for non-system applications, similar to the way that pip can be used in a virtualenv. You would set RootDir to somewhere that you have write access to (/home/wgiokas/foo) and, get it set up for pacman (add the directories it needs) and then run it with --noroot. Pacman is going to error itself now if it can't write files.
In conclusion, I'd like to see a very well thought out plan discussed before I look at code for this. Alright, I'll keep working on stuff. Thanks for the feedback, though. There's still a whole lot more that I've found that needs to be changed to use this to extract and work with packages as a non-root user.
Thanks,
participants (4)
-
Allan McRae
-
hauptmech
-
Ido Rosen
-
William Giokas