ฉันจะตรวจสอบได้อย่างไรว่าเชลล์ควบคุมจาก SSH


69

ฉันต้องการตรวจจับจากเชลล์สคริปต์ (โดยเฉพาะอย่างยิ่ง. zshrc) หากมีการควบคุมผ่าน SSH ฉันลองตัวแปร HOST แต่มักจะเป็นชื่อของคอมพิวเตอร์ที่ใช้เชลล์อยู่เสมอ ฉันสามารถเข้าถึงชื่อโฮสต์ที่มาจากเซสชัน SSH ได้หรือไม่ การเปรียบเทียบทั้งสองจะช่วยแก้ปัญหาของฉัน

ทุกครั้งที่ฉันเข้าสู่ระบบจะมีข้อความระบุเวลาเข้าสู่ระบบและโฮสต์ล่าสุด:

Last login: Fri Mar 18 23:07:28 CET 2011 from max on pts/1
Last login: Fri Mar 18 23:11:56 2011 from max

นี่หมายความว่าเซิร์ฟเวอร์มีข้อมูลนี้

คำตอบ:


90

นี่คือเกณฑ์ที่ฉันใช้ใน~/.profile:

  • หากหนึ่งในตัวแปรSSH_CLIENTหรือSSH_TTYกำหนดไว้มันเป็นเซสชัน ssh
  • หากชื่อกระบวนการหลักของเชลล์ล็อกอินคือนั่นคือsshdเซสชัน ssh
if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then
  SESSION_TYPE=remote/ssh
# many other tests omitted
else
  case $(ps -o comm= -p $PPID) in
    sshd|*/sshd) SESSION_TYPE=remote/ssh;;
  esac
fi

(ทำไมคุณต้องการทดสอบสิ่งนี้ในการกำหนดค่าเชลล์ของคุณแทนที่จะเริ่มต้นเซสชัน)


3
ทำงานได้ดีมากขอบคุณ! github.com/balupton/dotfiles/commit/…
balupton

1
คุณอาจต้องการทำสิ่งนี้ในการกำหนดค่าเชลล์ของคุณหากคุณต้องการเปิดใช้งานการส่งต่อเอเจนต์ ssh จากเชลล์ระยะไกลของคุณ (เนื่องจาก vars สภาพแวดล้อมจำเป็นต้องตั้งค่าในแต่ละเชลล์ที่คุณต้องการส่งต่อจาก)
ต่ำกว่า

@underrun ฉันไม่เข้าใจประเด็นของคุณ .profileหากคุณใช้เปลือกอีกในเซสชั่นเดียวกันก็สืบทอดตัวแปรสภาพแวดล้อมที่กำหนดโดย และสิ่งนี้เกี่ยวข้องกับการส่งต่อตัวแทน?
Gilles

1
@underrun หากคุณต้องการทดสอบการมีอยู่ของการส่งต่อตัวแทน SSH ให้ทดสอบSSH_AUTH_SOCKตัวแปร แต่ทำไมคุณถึงเรียกใช้ตัวแทน SSH ในกรณีนั้น คุณหมายถึงเริ่มตัวแทนถ้าคุณเข้าสู่ระบบโดยไม่ต้องส่งตัวแทน ทำไมไม่เริ่มตัวแทนถ้าไม่มีหนึ่ง ( [ -n "$SSH_AUTH_SOCK" ] || eval $(ssh-agent))?
Gilles

1
@Praxeolitic SSH_*ตัวแปรถูกตั้งค่าใน subprocesses ของเชลล์ที่อยู่ที่ส่วนหัวของเซสชัน SSH เช่นถ้าคุณเริ่มเซสชันหน้าจอผ่าน SSH (คุณควรยกเลิกการตั้งค่าตัวแปรก่อนเริ่มเซสชันหากคุณสนใจ) ฉันคิดว่าเหตุผลสำหรับการทดสอบกระบวนการหลักคือฉันเริ่มทำก่อนที่ sshd จะกำหนดตัวแปรสภาพแวดล้อมใด ๆ
Gilles

21

คุณควรจะสามารถตรวจสอบผ่านทางSSH_TTY, SSH_CONNECTIONหรือSSH_CLIENTตัวแปร


1
นอกจากนี้ยังเพิ่มสิ่งเหล่านี้env_keepในsudoersเพื่อให้สามารถใช้งานได้กับsuคำสั่ง :)
Thomas G.

10

ฉันเพิ่งมีปัญหาเดียวกันใน Linux โดยใช้ Bash ครั้งแรกที่ผมใช้ในสภาพแวดล้อม SSH_CONNECTION ตัวแปร su -แต่แล้วก็รู้ว่ามันไม่ได้ตั้งค่าถ้าคุณ

การแก้ปัญหาดังกล่าวข้างต้น lastlog ไม่ได้ทั้งหลังหรือsusu -

ในที่สุดฉันกำลังใช้who am iซึ่งแสดง IP ระยะไกล (หรือชื่อโฮสต์) ที่ท้ายถ้าเป็นการเชื่อมต่อ SSH นอกจากนี้ยังใช้งานได้หลังจาก su

ด้วยการใช้นิพจน์ปกติของ Bash การทำงานนี้:

if [[ $(who am i) =~ \([-a-zA-Z0-9\.]+\)$ ]] ; then echo SSH; else echo no; fi

หาก zsh ไม่สนับสนุนการแสดงออกปกติสามารถทำได้ในหลาย ๆ ทางด้วย grep, cut, sed หรืออะไรก็ตาม

สำหรับคนที่อยากรู้อยากเห็นด้านล่างคือสิ่งที่ฉันใช้สำหรับใน. bashrc ของรูท:

    # We don't allow root login over ssh.
    # To enable root X forwarding if we are logged in over SSH, 
    # use the .Xauthority file of the user who did su

    w=$(who am i)
    if [[ $w =~ \([-a-zA-Z0-9\.]+\)$ ]] ; then
        olduser=${w/ .*/}
        oldhome=$(getent passwd $olduser | cut -d: -f 6)
        [ -f "$oldhome/.Xauthority" ] \
          && export XAUTHORITY=$oldhome/.Xauthority
    fi

ทางเลือกอื่นที่ใช้งานได้กับsuก็คือการค้นหาซ้ำsshdผ่านกระบวนการหลัก:

#!/bin/bash

function is_ssh() {
  p=${1:-$PPID}
  read pid name x ppid y < <( cat /proc/$p/stat )
  # or: read pid name ppid < <(ps -o pid= -o comm= -o ppid= -p $p) 
  [[ "$name" =~ sshd ]] && { echo "Is SSH : $pid $name"; return 0; }
  [ "$ppid" -le 1 ]     && { echo "Adam is $pid $name";  return 1; }
  is_ssh $ppid
}

is_ssh $PPID
exit $?

หากฟังก์ชั่นถูกเพิ่มเข้าไปใน. bashrc ก็สามารถใช้เป็น if is_ssh; then ...


1
ไม่ทำงานในtmuxเซสชันระยะไกลและมีปัญหาหากลงชื่อเข้าใช้ผ่าน IPv6 และไม่มีชื่อย้อนกลับ DNS อยู่
bene

@bene: สิ่งที่ไม่ทำงาน? การแสดงออกปกติหรือwho am iไม่แสดงที่อยู่ IPv6 ของคุณ?
mivk

1) who am iไม่ส่งคืนสิ่งใดในtmuxเซสชันระยะไกล 2) ที่อยู่ IPv6 อาจมีเครื่องหมายทวิภาคที่ regex ของคุณไม่อนุญาต นี่อาจเป็นเรื่องยุ่งยากเนื่องจากwho am iมี(:0.0)อยู่ในเซสชัน X สำหรับฉัน (xterm)
ประโยชน์

@bene: โซลูชันทางเลือกที่ฉันเพิ่งเพิ่มควรทำงานกับ IPv6 ฉันไม่รู้เกี่ยวกับ tmux แต่ก็ใช้ได้screenเช่นกัน
mivk

7

ฉันคิดว่าคำตอบของ Gilles และ Cakemox นั้นดี แต่เพื่อความสมบูรณ์ ...

Last login: Fri Mar 18 23:07:28 CET 2011 from max on pts/1

มาจาก1pam_lastlog

คุณสามารถพิมพ์pam_lastlogข้อมูลโดยใช้คำสั่งlastlog2เช่น

$ lastlog -u mikel  
Username         Port     From             Latest
mikel            tty1                      Fri Jan 28 10:58:10 +1100 2011

สำหรับการเข้าสู่ระบบในท้องถิ่นเปรียบเทียบกับ

Username         Port     From             Latest
mikel            pts/9    mikel-laptop     Sat Mar 19 11:11:58 +1100 2011

สำหรับการเข้าสู่ระบบ SSH

ในระบบของฉันการทำงานนี้เพื่อแยก

$ lastlog -u mikel | sed -ne '2{p;q}' | cut -c 27-42
mikel-laptop 

lastและwอาจเป็นประโยชน์เช่นกัน

$ TTY=$(tty)
$ last -n 1 ${TTY#/dev/} | sed -ne '1{p;q}'
mikel    pts/12       :0.0             Sat Mar 19 11:29   still logged in 


1 ลินุกซ์ / FreeBSDpam_lastlogเอกสาร
2 man page Linux / FreeBSD lastlog(8)


1

เริ่มต้นด้วยการดูที่สภาพแวดล้อมของคุณและค้นหาตัวเลือกที่เหมาะสม

printenv|grep SSH
SSH_CLIENT=192.168.1.xxx
SSH_CONNECTION=192.168.1.xxx
SSH_TTY=/dev/ttys021

คุณสามารถขอตัวแปรสภาพแวดล้อมเหล่านี้จำนวนมากเพื่อเรียกใช้การกระทำที่เฉพาะเจาะจงตามสถานะของพวกเขา


-1

นี่คือการตรวจสอบการเชื่อมต่อที่กำหนดไว้ทั้งหมดจากผู้ใช้รายอื่นโดยใช้ SSH

netstat | grep ssh

สิ่งนี้ไม่น่าเชื่อถือเลย
DannyNiu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.