From c3608beb1b6da54f2e7b489571b750f582338f9f Mon Sep 17 00:00:00 2001 From: sev Date: Wed, 3 Mar 2021 01:14:34 -0600 Subject: [PATCH] code cleanup, add su support cleanup renames some internal vars, moves SSH/GPG setup back to .zshenv, and upgrades SSH setup to give more information about what it is doing. su support will allow you to switch to another user with a non-login shell and, as long as they are using zsh with the same dotfiles, you will get a proper environment set up as if it were a login shell; this is a lot easier and more comfortable than making an alias to or manually passing SSH_AUTH_AGENT and other vars via sudo... for now. an attempt should be made to make super user switching more portable by adding support for doas and bog-standard su in aliases and elsewhere. --- base/.zprofile | 44 +---------------- base/.zshenv | 127 +++++++++++++++++++++++++++++++++++++------------ base/.zshrc | 5 +- 3 files changed, 102 insertions(+), 74 deletions(-) diff --git a/base/.zprofile b/base/.zprofile index f028728..7a7fc10 100644 --- a/base/.zprofile +++ b/base/.zprofile @@ -2,10 +2,10 @@ ## reset PATH to prevent /etc/zprofile from changing it # some distros put non-interactive PATH in env and interactive PATH in profile; # we want to make sure to always use ours regardless -if [[ -v _sev_backup_path ]] { +if [[ -v _backup_path ]] { path=("${_backup_path[@]}" "${path[@]}") export PATH - unset _sev_backup_path + unset _backup_path } ## common export EDITOR=vim @@ -22,46 +22,6 @@ export PYTHONSTARTUP=~/.pythonrc ## perl [[ -v commands[perl] ]] && eval $(perl -I $XDG_DATA_HOME/perl5/lib/perl5 -Mlocal::lib=$XDG_DATA_HOME/perl5 2>/dev/null) -### ssh agents -# NOTE: preferred order of agents to check: okcagent, gnupg, openssh -# first block takes care of okcagent and openssh, second handles gnupg -if [[ ! -v SSH_AUTH_SOCK && ( -v commands[okc-ssh-agent] || - ( -v commands[ssh-agent] && ! -v commands[gpg] ) ) ]] { - okc=${commands[okc-ssh-agent]:+okc-} - agentfile=~/tmp/${okc}ssh-agent-exports - typeset sock= - typeset -i pid= - if [[ -f "$agentfile" ]] { - IFS=$'\0' read -r sock pid <"$agentfile" - } - if [[ -S "$sock" && $pid > 0 ]] && kill -0 $pid; then - echo "Reusing agent pid $pid" - export SSH_AUTH_SOCK="$sock" - export SSH_AGENT_PID=$pid - else - # TODO: ensure ssh-agent path looks legit - # to avoid unsafe eval? - eval `${okc}ssh-agent` - echo -n "$SSH_AUTH_SOCK"$'\0'$SSH_AGENT_PID >!$agentfile - fi - unset okc agentfile sock pid -} elif [[ -v commands[gpg] && ! -S $_GNUPG_SOCK_DEST && \ - ( ! -v SSH_AUTH_SOCK || -v DISPLAY ) ]] { - export GPG_TTY=$(tty) - export PINENTRY_USER_DATA=USE_TTY=$((!${+DISPLAY})) - gpg-connect-agent UPDATESTARTUPTTY /bye >/dev/null 2>&1 - gpg-connect-agent /subst /serverpid \ - '/echo GPG agent pid ${get serverpid}' /bye - [[ ! -v SSH_AUTH_SOCK ]] && \ - export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) -} - -### gpg socket -if [[ -v _GNUPG_SOCK_SRC && -v _GNUPG_SOCK_DEST && -S $_GNUPG_SOCK_DEST ]] { - unlink $_GNUPG_SOCK_SRC >/dev/null 2>&1 - mv $_GNUPG_SOCK_DEST $_GNUPG_SOCK_SRC >/dev/null -} - ### load site-specific if [[ -f ~/.zprofile.local ]] { source ~/.zprofile.local } diff --git a/base/.zshenv b/base/.zshenv index 819eb70..8add817 100644 --- a/base/.zshenv +++ b/base/.zshenv @@ -1,21 +1,33 @@ -### exports for new non-interactive shell -if [[ $SHLVL == 1 ]] { +### unset unwanted options that could be set in /etc/zshenv +unsetopt SH_WORD_SPLIT KSH_ARRAYS + +### check if su +if [[ -v _sev_olduser && $_sev_olduser != $USERNAME ]] _sev_reset_shell= +export _sev_olduser=$USERNAME + +### exports for all new shells +if [[ -v _sev_reset_shell || $SHLVL == 1 ]] { ## lang export CHARSET=UTF-8 - export LANG="en_US.UTF-8" - export LC_CTYPE="$LANG" + export LANG=en_US.UTF-8 + export LC_CTYPE=$LANG ## path + typeset -U path fpath + if [[ $SHLVL == 1 ]] { + # take a backup before any customizations + export _sev_sys_PATH=$PATH + export _sev_sys_FPATH=$FPATH + } # /usr/{pkg,local,games} are unix/bsdisms - typeset -U PATH path path=({~/,/,/usr/}sbin {~/,/,/usr/}bin /usr/pkg/{s,}bin /usr/X11R{7,6}/bin - /usr/local/{s,}bin /usr/games "${path[@]}") - export PATH - typeset -U _sev_backup_path - _sev_backup_path=("${path[@]}") - typeset -U FPATH fpath - fpath=(${ZDOTDIR:-$HOME/.zsh}/functions/{*,Completions/*}(N) "${fpath[@]}") - export FPATH + /usr/local/{s,}bin /usr/games) + PATH=$PATH:$_sev_sys_PATH + fpath=(${ZDOTDIR:-$HOME/.zsh}/functions/{*,Completions/*}(N)) + FPATH=$FPATH:$_sev_sys_FPATH + # take another backup, explained in .zprofile + typeset -U _backup_path + _backup_path=("${path[@]}") ## xdg export XDG_CONFIG_HOME=~/etc @@ -25,33 +37,88 @@ if [[ $SHLVL == 1 ]] { export XDG_CACHE_HOME=~/tmp export XDG_RUNTIME_DIR=~/tmp - # create tmp link - t="${TMPDIR:-/tmp}/home-$LOGNAME" - h="$HOME/tmp" - if [[ ! -e "$t" ]] { - mkdir -m 700 "$t" > /dev/null 2>&1 + ## create tmp link + t=${TMPDIR:-/tmp}/home-$LOGNAME + h=$HOME/tmp + if [[ ! -e $t ]] { + mkdir -m 700 $t > /dev/null 2>&1 # TODO: check if dir exists after mkdir } # allow opaque entries to override link creation - if [[ ! -e "$h" ]] { - ln -sf "$t" "$h" > /dev/null 2>&1 + if [[ ! -e $h ]] { + ln -sf $t $h > /dev/null 2>&1 } unset t h -} -### gpg ssh forwarding -# these env vars are used as arguments to RemoteForward in ~/.ssh/config -if [[ -v commands[gpgconf] && ! ( -v _GNUPG_SOCK_SRC && -v _GNUPG_SOCK_DEST ) ]] { - # if already connected over SSH, reuse forwarded socket for future - # connections; else use extra socket - sock=${SSH_CLIENT:+agent-socket} - export _GNUPG_SOCK_SRC=$(gpgconf --list-dirs ${sock:-agent-extra-socket}) - # XXX: chance of race condition - export _GNUPG_SOCK_DEST=/tmp/.gpg-agent-forward - unset sock + ## ssh agents + # NOTE: preferred order of agents to check: okcagent, gnupg, openssh + # first block takes care of okcagent and openssh, second gnupg + print -nP "%F{blue}>>>%f SSH: %F{green}" + if [[ ! -v SSH_AUTH_SOCK && ( -v commands[okc-ssh-agent] || + ( -v commands[ssh-agent] && ! -v commands[gpg] ) ) ]] { + okc=${commands[okc-ssh-agent]:+okc-} + agentfile=~/tmp/${okc}ssh-agent-exports + typeset sock= + typeset -i pid= + if [[ -f $agentfile ]] { + IFS=$'\0' read -r sock pid <$agentfile + } + if [[ -S $sock && $pid > 0 ]] && kill -0 $pid; then + echo "Reusing agent pid $pid" + export SSH_AUTH_SOCK=$sock + export SSH_AGENT_PID=$pid + else + # TODO: ensure ssh-agent path looks legit + # to avoid unsafe eval? + eval `${okc}ssh-agent` + echo -n $SSH_AUTH_SOCK$'\0'$SSH_AGENT_PID >!$agentfile + fi + unset okc agentfile sock pid + } elif [[ -v commands[gpg] && ! -S $_GNUPG_SOCK_DEST && \ + ( ! -v SSH_AUTH_SOCK || -v DISPLAY ) ]] { + export GPG_TTY=$(tty) + export PINENTRY_USER_DATA=USE_TTY=$((!${+DISPLAY})) + gpg-connect-agent UPDATESTARTUPTTY /bye >/dev/null 2>&1 + gpg-connect-agent /subst /serverpid \ + '/echo GPG agent pid ${get serverpid}' /bye + [[ ! -v SSH_AUTH_SOCK ]] && \ + export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) + } else { + echo "Pre-existing or remote agent" + } + + ## gpg ssh forwarding + # ssh automatically tunnels SSH_AUTH_SOCK with the right config, but GPG + # doesn't—we use a RemoteForward rule in ~/.ssh/config that uses these env + # vars to push the gpg extra socket through when connecting via ssh + # HACK: this entire thing sucks but there is no other easy way that works + # out of the box with other systems + if [[ -v commands[gpgconf] ]] { + # if already connected over SSH, reuse forwarded socket for future + # connections; else use extra socket + sock=${SSH_CLIENT:+agent-socket} + export _GNUPG_SOCK_SRC=$(gpgconf --list-dirs ${sock:-agent-extra-socket}) + unset sock + # XXX: multiple SSH sessions to the same host will overwrite this + # socket, no way to send unique paths without configuring explicit + # SendEnv and AcceptEnv exclusions on client and host respectively + export _GNUPG_SOCK_DEST=/tmp/.gpg-agent-forward + # if socket exists already, we are on a RemoteForwarded client, so copy + # it over so that GPG sees it + # XXX: race condition if connecting multiple terminals at once + if [[ -S $_GNUPG_SOCK_DEST ]] { + unlink $_GNUPG_SOCK_SRC >/dev/null 2>&1 + mv $_GNUPG_SOCK_DEST $_GNUPG_SOCK_SRC >/dev/null + } + } } ### load site-specific if [[ -f ~/.zshenv.local ]] { source ~/.zshenv.local } +### source .zprofile +# if we used su, without --login, let's run zprofile ourselves +# XXX: system zprofile is not run +if [[ -v _sev_reset_shell || $SHLVL == 1 ]] source ~/.zprofile + # vim: set et sts=4 sw=4 ts=8 tw=79 : diff --git a/base/.zshrc b/base/.zshrc index 090d7fa..014b039 100644 --- a/base/.zshrc +++ b/base/.zshrc @@ -37,12 +37,13 @@ if (( $#terminfo == 0 )) { if [[ -n $keymap ]] { source $keymap } else { - echo "Failed to source file $keymap" >&2 + echo "Failed to source keymap file $keymap" >&2 } unfunction find_keymap; unset keymap } else { # activate application mode for zle so terminfo keys work - # don't do this for zkbd since application mode shouldn't have ben enabled + # NOTE: don't do this for zkbd since application mode shouldn't have been + # enabled by zkbd when the keymap file was generated if [[ -v terminfo[smkx] && -v terminfo[rmkx] ]] { autoload -Uz add-zle-hook-widget function _enter-application-mode { echoti smkx } -- 2.47.0