Cette question a été posée d'une manière différente dans d'autres forums. Mais il n'y a pas eu d'explication décente pour laquelle vous ne pouvez pas faire ce qui suit en bash.
#!/bin/bash
command1
SWITCH_USER_TO rag
command2
command3
Habituellement, la manière suggérée est
#!/bin/bash
command1
sudo -u rag command2
sudo -u rag command3
mais pourquoi n'est-il pas possible bash
de passer à un autre utilisateur à un moment donné lors de l'exécution du script bash et d'exécuter le reste des commandes en tant qu'utilisateur différent?
Réponses:
Les informations figurent déjà dans mon autre réponse , mais elles sont un peu enfouies là-bas. Alors j'ai pensé, je l'ajouterais ici.
bash
n'a pas de disposition pour changer les utilisateurs, mais lezsh
fait.Dans
zsh
, vous modifiez les utilisateurs en affectant des valeurs à ces variables:$EUID
: modifiez l'ID utilisateur effectif (et rien d'autre). Habituellement, vous pouvez changer votre euid entre votre véritable ID utilisateur et l'ID utilisateur de l'ensemble enregistré (s'il est appelé à partir d'un exécutable setuid) ou changer n'importe quoi si votre euid est 0.$UID
: modifiez l'ID utilisateur effectif, l'ID utilisateur réel et l'ID utilisateur d'ensemble enregistré à la nouvelle valeur. À moins que cette nouvelle valeur soit 0, il n'y a pas de retour, car une fois que tous les 3 ont été définis sur la même valeur, il n'y a aucun moyen de la changer pour autre chose.$EGID
et$GID
: même chose mais pour les identifiants de groupe.$USERNAME
. C'est comme utilisersudo
ousu
. Il définit votre euid, ruid, ssuid sur l'uid de cet utilisateur. Il définit également les groupes egid, rgid et ssgid et supplémentaires en fonction des appartenances aux groupes définies dans la base de données des utilisateurs. Comme pour$UID
, à moins que vous définissez$USERNAME
àroot
, il n'y a pas de retour, mais comme pour$UID
, vous pouvez changer l'utilisateur que pour un sous - shell.Si vous exécutez ces scripts en tant que "root":
Maintenant, pour changer d'utilisateur comme dans
sudo
ousu
, nous ne pouvons le faire qu'en utilisant des sous-coquilles, sinon nous ne pourrions le faire qu'une seule fois:la source
Offres de noyau
man 2 setuid
et amis.Maintenant, cela fonctionne sur le processus d'appel. Plus important encore, vous ne pouvez pas élever vos privilèges. C'est pourquoi
su
etsudo
que le bit SETUID est défini pour qu'ils s'exécutent toujours avec les privilèges les plus élevés (root
) et tombent sur l'utilisateur souhaité en conséquence.Cette combinaison signifie que vous ne pouvez pas changer l'UID du shell en exécutant un autre programme pour le faire (c'est pourquoi vous ne pouvez pas vous attendre à ce
sudo
qu'un autre programme le fasse) et vous ne pouvez pas (en tant que shell) le faire vous-même à moins que vous sont prêts à s'exécuter en tant que superutilisateur ou en tant que même utilisateur vers lequel vous souhaitez basculer, ce qui n'a pas de sens. De plus, une fois que vous avez supprimé les privilèges, il n'y a plus de retour possible.la source
Eh bien, vous pouvez toujours faire:
(ʘ‿ʘ)
Cela a d'abord commencé comme une blague car cela implémente ce qui est demandé, mais probablement pas exactement comme prévu, et n'est pas pratique. Mais comme cela a évolué vers quelque chose qui fonctionne dans une certaine mesure et implique quelques bons hacks, voici une petite explication:
Comme l'a dit Miroslav , si nous laissons de côté les capacités de style Linux (qui ne seraient pas vraiment utiles ici non plus), la seule façon pour un processus non privilégié de changer l'uid est d'exécuter un exécutable setuid.
Une fois que vous obtenez le privilège de superutilisateur (en exécutant un exécutable setuid dont le propriétaire est root par exemple), vous pouvez basculer l'ID utilisateur effectif entre votre ID utilisateur d'origine, 0 et tout autre ID, sauf si vous renoncez à votre ID utilisateur d'ensemble enregistré ( comme des choses comme
sudo
ousu
font typiquement).Par exemple:
Maintenant, j'ai une
env
commande qui me permet d'exécuter n'importe quelle commande avec un identifiant utilisateur efficace et un identifiant utilisateur enregistré de 0 (mon identifiant réel étant toujours 1000):perl
a des wrappers poursetuid
/seteuid
(ceux-ci$>
et les$<
variables).Zsh aussi:
Bien que ci-dessus, ces
id
commandes soient appelées avec un identifiant utilisateur réel et un identifiant utilisateur enregistré de 0 (bien que si j'avais utilisé mon./env
au lieu desudo
cela, cela n'aurait été que l'identifiant utilisateur enregistré, tandis que l'ID utilisateur réel serait resté 1000), ce qui signifie que s'il s'agissait de commandes non fiables, elles pourraient toujours faire des dégâts, vous devriez donc l'écrire à la place comme:(c'est-à-dire tous les uids (ensemble effectif, réel et enregistré) juste pour l'exécution de ces commandes.
bash
n'a aucun moyen de modifier les identifiants utilisateur. Donc, même si vous aviez un exécutable setuid avec lequel appeler votrebash
script, cela n'aiderait pas.Avec
bash
, il vous reste à exécuter un exécutable setuid chaque fois que vous voulez changer d'uid.L'idée dans le script ci-dessus est lors d'un appel à SWITCH_TO_USER, pour exécuter une nouvelle instance bash pour exécuter le reste du script.
SWITCH_TO_USER someuser
est plus ou moins une fonction qui exécute à nouveau le script en tant qu'utilisateur différent (en utilisantsudo
) mais en ignorant le début du script jusqu'àSWITCH_TO_USER someuser
.Là où cela devient difficile, c'est que nous voulons conserver l'état de la bash actuelle après avoir démarré la nouvelle bash en tant qu'utilisateur différent.
Décomposons-le:
Nous aurons besoin d'alias. L'une des astuces de ce script consiste à ignorer la partie du script jusqu'au
SWITCH_TO_USER someuser
, avec quelque chose comme:Ce formulaire est similaire à celui
#if 0
utilisé en C, c'est un moyen de commenter complètement du code.:
est un no-op qui retourne vrai. Donc en: || :
, le second:
n'est jamais exécuté. Cependant, il est analysé. Et<< 'xxx'
c'est une forme de document ici où (parce quexxx
c'est cité), aucune expansion ou interprétation n'est faite.On aurait pu faire:
Mais cela aurait signifié que le document ici aurait dû être écrit et transmis en tant que stdin à
:
.:||:
évite cela.Maintenant, où il devient hacky, c'est que nous utilisons le fait que les
bash
alias se développent très tôt dans son processus d'analyse. Avoirskip
un alias pour la:||: << 'SWITCH_TO_USER someuther'
partie de la construction de mise en commentaire .Continuons:
Voici la définition de la fonction SWITCH_TO_USER . Nous verrons ci-dessous que SWITCH_TO_USER sera éventuellement un alias enroulé autour de cette fonction.
Cette fonction fait l'essentiel de la réexécution du script. En fin de compte, nous voyons qu'il se ré-exécute (dans le même processus à cause de
exec
)bash
avec la_x
variable dans son environnement (nous l'utilisonsenv
ici carsudo
généralement assainit son environnement et ne permet pas de passer des vars env arbitraires à travers). Celabash
évalue le contenu de cette$_x
variable en tant que code bash et source le script lui-même._x
est défini précédemment comme:Toutes les
declare
,alias
,shopt -p
set +o
sortie constituent une décharge de l'état interne de la coquille. Autrement dit, ils vident la définition de toutes les variables, fonctions, alias et options sous forme de code shell prêt à être évalué. En plus de cela, nous ajoutons le réglage des paramètres de position ($1
,$2
...) en fonction de la valeur du$_a
tableau (voir ci-dessous), et un peu de nettoyage afin que l'énorme$_x
variable ne reste pas dans l'environnement pour le reste du script.Vous remarquerez que la première partie jusqu'à
set +x
est enveloppée dans un groupe de commandes dont stderr est redirigé vers/dev/null
({...} 2> /dev/null
). C'est parce que, si à un moment donné du scriptset -x
(ouset -o xtrace
) est exécuté, nous ne voulons pas que ce préambule génère des traces car nous voulons le rendre le moins intrusif possible. Nous exécutons donc unset +x
(après avoir pris soin de vider l'option (y comprisxtrace
) les paramètres au préalable) où les traces sont envoyées à / dev / null.Le
eval "$_X"
stderr est également redirigé vers / dev / null pour des raisons similaires, mais également pour éviter les erreurs d'écriture lors d'une tentative de lecture de variables spéciales en lecture seule.Continuons avec le script:
C'est notre astuce décrite ci-dessus. Lors de l'appel initial du script, il sera annulé (voir ci-dessous).
Maintenant, l'encapsuleur d'alias autour de SWITCH_TO_USER. La raison principale est de pouvoir passer les paramètres positionnels (
$1
,$2
...) au nouveaubash
qui interprétera le reste du script. Nous ne pouvions pas le faire dans laSWITCH_TO_USER
fonction car à l'intérieur"$@"
de la fonction, se trouvent les arguments des fonctions, pas ceux des scripts. La redirection stderr vers / dev / null consiste à nouveau à masquer les xtraces, eteval
à contourner un bogue dansbash
. Ensuite, nous appelons laSWITCH_TO_USER
fonction .Cette partie annule l'
skip
alias (le remplace par la:
commande no-op) sauf si la$_u
variable est définie.Voilà notre
skip
alias. Lors de la première invocation, ce sera juste:
(le no-op). Sur les invocations de re-subsequence, ce sera quelque chose comme::||: << 'SWITCH_TO_USER root'
.Donc, ici, à titre d'exemple, à ce stade, nous réinvoquons le script en tant
root
qu'utilisateur, et le script restaurera l'état enregistré, et sautera jusqu'à cetteSWITCH_TO_USER root
ligne et continuera.Cela signifie qu'il doit être écrit exactement comme stat, avec
SWITCH_TO_USER
au début de la ligne et avec exactement un espace entre les arguments.La plupart des états, stdin, stdout et stderr seront conservés, mais pas les autres descripteurs de fichiers car
sudo
généralement ils les ferment sauf s'ils sont explicitement configurés pour ne pas le faire. Ainsi, par exemple:ne fonctionnera généralement pas.
Notez également que si vous le faites:
Cela ne fonctionne que si vous avez le droit à
sudo
asalice
etalice
le droit àsudo
asbob
etbob
asroot
.Donc, en pratique, ce n'est pas vraiment utile. Utiliser à la
su
place desudo
(ou unesudo
configuration oùsudo
authentifie l'utilisateur cible au lieu de l'appelant) pourrait être un peu plus logique, mais cela signifierait toujours que vous auriez besoin de connaître les mots de passe de tous ces gars-là.la source
ioshcc
? Vous devriez avoir entré une seule ligne.La commande "sudo -u ram sh" peut être utilisée pour passer à l'utilisateur "ram", en exécutant la commande "sh" ou shell. La commande "exit" vous ramènera à l'utilisateur d'origine.
la source