Advertisement
devinteske

ssh-agent-dup

Jun 23rd, 2015
553
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 9.57 KB | None | 0 0
  1. # FILE: ~/.bash_profile
  2.  
  3. export SUCCESS=0
  4. export FAILURE=1
  5.  
  6. #
  7. # ... SNIP ...
  8. #
  9.  
  10. have() { type "$@" > /dev/null 2>&1; }
  11. eval2() { echo "$*"; eval "$@"; }
  12. : ${UNAME_S:=$(uname -s)}
  13.  
  14. #
  15. # ... SNIP ...
  16. #
  17.  
  18. DIALOG_MENU_TAGS="123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  19.  
  20. # dialog_menutag
  21. #
  22. # Obtain the menutag chosen by the user from the most recently displayed
  23. # dialog(1) menu and clean up any temporary files.
  24. #      
  25. dialog_menutag()
  26. {
  27.         local tmpfile="$DIALOG_TMPDIR/dialog.menu.$$"
  28.  
  29.         [ -f "$tmpfile" ] || return $FAILURE
  30.  
  31.         cat "$tmpfile" 2> /dev/null
  32.         quietly rm -f "$tmpfile"
  33.  
  34.         return $SUCCESS
  35. }
  36.  
  37. # dialog_menutag2help $tag_chosen $tag1 $item1 $help1 \
  38. #                                   $tag2 $item2 $help2
  39. #
  40. # To use the `--menu' option of dialog(1) with the `--item-help' option, you
  41. # must pass an ordered list of tag/item/help triplets on the command-line. When
  42. # the user selects a menu option the tag for that item is printed to stderr.
  43. #
  44. # This function allows you to dereference the tag chosen by the user back into
  45. # the help associated with said tag (item is discarded/ignored).
  46. #
  47. # Pass the tag chosen by the user as the first argument, followed by the
  48. # ordered list of tag/item/help triplets (HINT: use the same tag/item/help list
  49. # as was passed to dialog(1) for consistency).
  50. #
  51. # If the tag cannot be found, NULL is returned.
  52. #
  53. dialog_menutag2help()
  54. {
  55.         local tag="$1" tagn help
  56.         shift 1 # tag
  57.  
  58.         while [ $# -gt 0 ]; do
  59.                 tagn="$1"
  60.                 help="$3"
  61.                 shift 3 # tagn/item/help
  62.  
  63.                 if [ "$tag" = "$tagn" ]; then
  64.                         echo "$help"
  65.                         return $SUCCESS
  66.                 fi
  67.         done
  68.         return $FAILURE
  69. }
  70.  
  71. #
  72. # ... SNIP ...
  73. #
  74.  
  75. # ssh-agent-dup [-a]
  76. #
  77. # Provide a menu list of open/active ssh-agent sessions available to the
  78. # currently authenticated user. Allows the user to quickly duplicate access
  79. # to an ssh-agent launched in another interactive session on the same machine.
  80. #
  81. # This allows you to, for example:
  82. #
  83. #       (in shell session A)
  84. #       ssh-agent
  85. #       (in shell session B)
  86. #       ssh-agent-dup
  87. #       (now both sessions A and B can use the same agent)
  88. #
  89. # No menu is presented if only a single agent session is available (the open
  90. # session is duplicated for the active shell session). If more than one agent
  91. # is available, a menu is presented. The menu choice becomes the active agent.
  92. #
  93. # If `-a' is present, list all readable agent sockets, not just those owned by
  94. # the currently logged-in user.
  95. #
  96. ssh-agent-dup()
  97. {
  98.         local function=ssh-agent-dup
  99.         local list_all=
  100.         local sockets=
  101.         local owner socket socket_owner pid current_user
  102.  
  103.         local OPTIND=1 OPTARG flag
  104.         while getopts "a" flag; do
  105.                 case "$flag" in
  106.                 a) list_all=1 ;;
  107.                 \?|*)
  108.                         echo "$function [-a]" >&2
  109.                         return $FAILURE
  110.                 esac
  111.         done
  112.         shift $(( $OPTIND - 1 ))
  113.  
  114.         case "$UNAME_S" in
  115.         *BSD) owner="-f%Su" ;;
  116.         *) owner="-c%U"
  117.         esac
  118.  
  119.         current_user=$( id -nu )
  120.         for socket in /tmp/ssh-*/agent.[0-9]*; do
  121.                 # Must exist as a socket
  122.                 [ -S "$socket" ] || continue
  123.  
  124.                 # Must end in numbers-only (after trailing dot)
  125.                 pid="${socket##*.}"
  126.                 [ "$pid" -a "$pid" = "${pid#*[!0-9]}" ] || continue
  127.                 pid=$(( $pid + 1 )) # socket num is one below agent PID
  128.  
  129.                 # Must be a running pid and an ssh-agent
  130.                 kill -0 $pid || continue
  131.                 [ "$( ps -p $pid -o ucomm= )" = "ssh-agent" ] || continue
  132.  
  133.                 # Must be owned by the current user unless `-a' is used
  134.                 # NB: When `-a' is used, the socket still has to be readable
  135.                 if [ ! "$list_all" ]; then
  136.                         socket_owner=$( stat $owner "$socket" ) || continue
  137.                         [ "$socket_owner" = "$current_user" ] || continue
  138.                 fi
  139.  
  140.                 sockets="$sockets $socket"
  141.         done
  142.  
  143.         sockets="${sockets# }"
  144.         if [ ! "$sockets" ]; then
  145.                 echo "$function: No agent sockets available" >&2
  146.                 return $FAILURE
  147.         fi
  148.         if [ "${sockets}" = "${sockets%% *}" ]; then
  149.                 # Only one socket found
  150.                 eval2 export SSH_AUTH_SOCK="$sockets" \
  151.                              SSH_AGENT_PID="$(( ${sockets##*.} + 1 ))"
  152.                 return $SUCCESS
  153.         fi
  154.  
  155.         #
  156.         # If we don't have dialog(1), just print the possible values
  157.         #
  158.         if ! have dialog; then
  159.                 local prefix="%3s"
  160.                 local fmt="$prefix %-16s %3s %s\n"
  161.                 local num=0 choice
  162.                 local identities nloaded
  163.  
  164.                 sockets=$( ls -tr $sockets ) # ascending order by age
  165.                 printf "$fmt" "" USER CNT COMMAND
  166.                 for socket in $sockets; do
  167.                         num=$(( $num + 1 ))
  168.                         pid=$(( ${socket##*.} + 1 ))
  169.                         nkeys=0
  170.                         identities=$( SSH_AUTH_SOCK="$socket" ssh-add -l ) &&
  171.                                 nkeys=$( echo "$identities" | grep -c . )
  172.                         printf "$fmt" $num: "$( ps -p $pid -o user= )" \
  173.                                 "$nkeys" "$( ps -p $pid -o command= )"
  174.                         printf "$prefix export %s %s\n" "" \
  175.                                 SSH_AUTH_SOCK="$socket" \
  176.                                 SSH_AGENT_PID="$pid"
  177.                 done
  178.                 echo
  179.                 read -p "Select a number [$num]: " choice
  180.                 : ${choice:=$num}
  181.                 case "$choice" in
  182.                 ""|*[!0-9]*)
  183.                         echo "$function: Invalid choice [$choice]" >&2
  184.                         return $FAILURE ;;
  185.                 esac
  186.                 if [ $choice -gt $num -o $choice -lt 1 ]; then
  187.                         echo "$function: Choice out of range [$choice]" >&2
  188.                         return $FAILURE
  189.                 fi
  190.                 set -- $sockets
  191.                 eval socket=\"\${$choice}\"
  192.  
  193.                 pid=$(( ${socket##*.} + 1 ))
  194.                 eval2 export SSH_AUTH_SOCK="$socket" SSH_AGENT_PID="$pid"
  195.         else
  196.                 local menu_list=
  197.  
  198.                 sockets=$( ls -1t $sockets ) # descending order by age
  199.                 menu_list=$(
  200.                         echo "$sockets" | awk -v tags="$DIALOG_MENU_TAGS" '
  201.                        {
  202.                                if (++tagn > length(tags)) exit
  203.                                if (!match($0, /[[:digit:]]+$/)) next
  204.                                pid = substr($0, RSTART, RLENGTH) + 1
  205.                                cmd = sprintf("ps -p %u -o user=", pid)
  206.                                cmd | getline user
  207.                                close(cmd)
  208.                                cmd = sprintf("ps -p %u -o command=", pid)
  209.                                cmd | getline command
  210.                                close(cmd)
  211.                                nloaded = 0
  212.                                cmd = "SSH_AUTH_SOCK=" $0 " ssh-add -l"
  213.                                while (cmd | getline identity) {
  214.                                        nloaded += identity ~ /^[[:digit:]]/
  215.                                }
  216.                                close(cmd)
  217.                                printf "'\'%s\'\ \'%s\'\ \'%s\''\n",
  218.                                        substr(tags, tagn, 1),
  219.                                        sprintf("pid %u %s+%u %s",
  220.                                                pid, user, nloaded, command),
  221.                                        sprintf("export %s %s",
  222.                                                "SSH_AUTH_SOCK=" $0,
  223.                                                "SSH_AGENT_PID=" pid)
  224.                        }'
  225.                 )
  226.  
  227.                 eval dialog \
  228.                         --clear --title "'$function'" --item-help \
  229.                         --menu "'Pick an ssh-agent to duplicate:'" 17 55 9 \
  230.                         $menu_list \
  231.                         2> "$DIALOG_TMPDIR/dialog.menu.$$"
  232.                 local retval=$?
  233.  
  234.                 # Return if "Cancel" was chosen (-1) or ESC was pressed (255)
  235.                 [ $retval -eq $SUCCESS ] || return $retval
  236.  
  237.                 local tag="$( dialog_menutag )"
  238.                 eval2 $( eval dialog_menutag2help "'$tag'" $menu_list )
  239.         fi
  240.  
  241.         # Attempt to dump fingerprints from newly configured agent
  242.         ssh-add -l
  243. }
  244.  
  245. #
  246. # ... SNIP ...
  247. #
  248.  
  249. # ssh-agent [ssh-agent options]
  250. #
  251. # Override ``ssh-agent'' to call a function (you can always call the real
  252. # binary by executing /usr/bin/ssh-agent) that launches a background ssh-agent
  253. # that times-out in 30 minutes.
  254. #
  255. # Will evaluate the output of /usr/bin/ssh-agent (the real ssh-agent) called
  256. # with either a known-secure set of arguments (if none are provided) or the
  257. # unmodified arguments to this functin.
  258. #
  259. # Purpose is to prevent memorizing something like ``eval "$( ssh-agent ... )"''
  260. # but instead simply ``ssh-agent [...]''.
  261. #
  262. # This allows you to, for example:
  263. #
  264. #   ssh-agent
  265. #   : do some ssh-add
  266. #   : do some commits
  267. #   ssh-agent -k
  268. #   : or instead of ``ssh-agent -k'' just wait 30m for it to die
  269. #
  270. ssh-agent()
  271. {
  272.     [ $# -gt 0 ] || set -- -t 1800
  273.     eval "$( /usr/bin/ssh-agent "$@" )"
  274. }
  275.  
  276. #
  277. # ... SNIP ...
  278. #
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement