summaryrefslogtreecommitdiff
path: root/sux
blob: 75c7449d1d7cf38b298a6d2996995e4b5b7b81d6 (plain)
  1. #!/bin/sh
  2. # Written by Francois Gouget, fgouget@free.fr
  3. # With many thanks to Daniel Martin and Falk Hueffner for their help
  4. # How to transfer cookies for root. See the sux_cookie_transfer variable
  5. # for options. Note that use-xauthority may not work if home directories
  6. # are on NFS. In such a case, change the default to copy-cookies.
  7. sux_root_cookie_transfer="c"
  8. usage()
  9. {
  10. echo "usage: `basename $0` [-m|-p|--preserve-environment]" >&2
  11. echo " [--display display]" >&2
  12. echo " [--no-cookies|--copy-cookies|--use-xauthority]" >&2
  13. echo " [--untrusted] [--timeout x]" >&2
  14. echo " [-] [username [command]]" >&2
  15. exit 2
  16. }
  17. ##
  18. # Process the sux options
  19. sux_su_opts=""
  20. sux_preserve=""
  21. sux_got_minus=0
  22. # "" -> default, n -> no-cookies, c -> copy-cookies, x -> use-xauthority
  23. sux_cookie_transfer=""
  24. sux_username=""
  25. sux_untrusted=""
  26. sux_timeout=""
  27. while [ $# -gt 0 ]
  28. do
  29. if [ "$sux_got_minus" = "1" ]
  30. then
  31. # Username follows "-"
  32. sux_username="$1"
  33. sux_su_opts="$sux_su_opts $1"
  34. shift
  35. # The remainder is the command to be executed
  36. break
  37. elif [ "$1" = "-" ]
  38. then
  39. # Last option before the username
  40. sux_su_opts="$sux_su_opts $1"
  41. sux_got_minus=1
  42. shift
  43. elif [ "$1" = "-m" -o "$1" = "-p" -o "$1" = "--preserve-environment" ]
  44. then
  45. sux_preserve="1"
  46. sux_su_opts="$sux_su_opts $1"
  47. shift
  48. elif [ "$1" = "--display" ]
  49. then
  50. if [ $# -lt 2 ]
  51. then
  52. echo "--display takes a display name as an argument" >&2
  53. usage # exits
  54. fi
  55. export DISPLAY="$2"
  56. shift 2
  57. elif [ "$1" = "--no-cookies" ]
  58. then
  59. if [ -n "$sux_cookie_transfer" -a "$sux_cookie_transfer" != "n" ]
  60. then
  61. echo "--no-cookies is incompatible with --copy-cookies and --use-xauthority" >&2
  62. usage # exits
  63. fi
  64. sux_cookie_transfer="n"
  65. shift
  66. elif [ "$1" = "--copy-cookies" ]
  67. then
  68. if [ -n "$sux_cookie_transfer" -a "$sux_cookie_transfer" != "c" ]
  69. then
  70. echo "--copy-cookies is incompatible with --no-cookies and --use-xauthority" >&2
  71. usage # exits
  72. fi
  73. sux_cookie_transfer="c"
  74. shift
  75. elif [ "$1" = "--use-xauthority" ]
  76. then
  77. if [ -n "$sux_cookie_transfer" -a "$sux_cookie_transfer" != "x" ]
  78. then
  79. echo "--use-xauthority is incompatible with --no-cookies and --copy-cookies" >&2
  80. usage # exits
  81. fi
  82. sux_cookie_transfer="x"
  83. shift
  84. elif [ "$1" = "--untrusted" ]
  85. then
  86. sux_untrusted="untrusted"
  87. shift
  88. elif [ "$1" = "--timeout" ]
  89. then
  90. if [ $# -lt 2 ]
  91. then
  92. echo "--timeout takes a timeout in seconds" >&2
  93. usage # exits
  94. fi
  95. sux_timeout="timeout $2"
  96. shift 2
  97. elif [ "$1" = "-?" ]
  98. then
  99. usage # exits
  100. else
  101. # First non-option is the username
  102. sux_username="$1"
  103. sux_su_opts="$sux_su_opts $1"
  104. shift
  105. # The remainder is the command to be executed
  106. break
  107. fi
  108. done
  109. ##
  110. # Get rid of the simple case
  111. if [ -z "$DISPLAY" ]
  112. then
  113. # If DISPLAY is not set we can take a shortcut...
  114. if [ -n "$sux_untrusted" -o -n "$sux_timeout" ]
  115. then
  116. echo "--untrusted and --timeout are only supported if DISPLAY is set" >&2
  117. usage #exits
  118. fi
  119. exec su $sux_su_opts "$@"
  120. fi
  121. ##
  122. # Do some option checking
  123. if [ -z "$sux_username" ]
  124. then
  125. sux_username="root"
  126. fi
  127. if [ -z "$sux_cookie_transfer" ]
  128. then
  129. if [ "$sux_username" = "root" ]
  130. then
  131. sux_cookie_transfer="$sux_root_cookie_transfer"
  132. else
  133. sux_cookie_transfer="c"
  134. fi
  135. fi
  136. if [ "$sux_cookie_transfer" = "x" -a "$sux_username" != "root" ]
  137. then
  138. echo "Only root can use --use-xauthority" >&2
  139. usage # exits
  140. fi
  141. ##
  142. # Create new cookies / retrieve the existing ones if necessary
  143. if [ -n "$sux_untrusted" -o -n "$sux_timeout" ]
  144. then
  145. if [ "$sux_cookie_transfer" != "c" ]
  146. then
  147. echo "--no-cookies/--use-xauthority are incompatible with --untrusted/--timeout" >&2
  148. usage #exits
  149. fi
  150. # Yeah, tempfile is a debian-specific command. Workarounds exist for
  151. # other machines. If you do use a workaround, be certain that said
  152. # workaround actually creates the new file, (via touch or similar) or
  153. # xauth (below) will produce a pointless warning message.
  154. sux_tmpfile=`tempfile -p sux`
  155. xauth -q -f $sux_tmpfile generate $DISPLAY . $sux_untrusted $sux_timeout
  156. sux_xauth_data=`xauth -f $sux_tmpfile nlist $DISPLAY`
  157. rm -f $sux_tmpfile
  158. fi
  159. ##
  160. # Build the command to restore the cookies in the su
  161. if [ "$sux_cookie_transfer" = "c" ]
  162. then
  163. # --copy-cookies case. We copy the cookie(s) using the xauth command.
  164. # If display is of the form "host:x.y" we may also need to get the
  165. # cookies for "host/unix:x.y".
  166. sux_unix_display=`echo $DISPLAY | sed -e 's#^\([a-zA-Z_.][a-zA-Z_.]*\):#\1/unix:#'`
  167. if [ "$DISPLAY" = "$sux_unix_display" ]
  168. then
  169. sux_unix_display=""
  170. fi
  171. # Get the cookies if we don't have them already
  172. if [ -z "$sux_xauth_data" ]
  173. then
  174. # Get the cookies. Note that we may need to
  175. sux_xauth_data=`xauth -q nlist $DISPLAY`
  176. if [ -n "$sux_unix_display" ]
  177. then
  178. sux_xauth_data="$sux_xauth_data `xauth -q nlist $sux_unix_display`"
  179. fi
  180. fi
  181. # We highjack the TERM environment variable to transfer the cookies to the
  182. # other user. We do this so that they never appear on any command line, and
  183. # because TERM appears to be the only environment variable that is not
  184. # reset by su. Then, as long as 'echo' is a shell builtin, these cookies
  185. # will never appear as command line arguments which means noone will be
  186. # able to intercept them (assuming they were safe in the first place).
  187. sux_term="TERM='$TERM'"
  188. # now we can store the script that will restore the cookies on the other
  189. # side of the su, in TERM!
  190. # Remove the old cookies. They may cause trouble if we transfer only one
  191. # cookie, e.g. an MIT cookie, and there's still a stale XDM cookie hanging
  192. # around.
  193. export TERM="xauth -q remove $DISPLAY 2>/dev/null;"
  194. if [ -n "$sux_unix_display" ]
  195. then
  196. TERM="$TERM xauth -q remove $sux_unix_display;"
  197. fi
  198. # Note that there may be more than one cookie to transfer, hence
  199. # this loop
  200. sux_i=0
  201. for sux_str in $sux_xauth_data
  202. do
  203. if [ $sux_i -eq 0 ]
  204. then
  205. TERM="$TERM echo $sux_str"
  206. else
  207. TERM="$TERM $sux_str"
  208. fi
  209. sux_i=`expr $sux_i + 1`
  210. if [ $sux_i -eq 9 ]
  211. then
  212. TERM="$TERM | xauth nmerge - ;"
  213. sux_i=0
  214. fi
  215. done
  216. sux_xauth_cmd="eval \$TERM;"
  217. sux_xauthority=""
  218. elif [ "$sux_cookie_transfer" = "x" ]
  219. then
  220. # --use-xauthority case. For root we can simplify things and simply
  221. # access the original user's .Xauthority file.
  222. sux_term=""
  223. sux_xauth_cmd=""
  224. if [ -n "$XAUTHORITY" ]
  225. then
  226. sux_xauthority="XAUTHORITY='$XAUTHORITY'"
  227. else
  228. sux_xauthority="XAUTHORITY='$HOME/.Xauthority'"
  229. fi
  230. else
  231. # --no-cookies case. We just transfer $DISPLAY and assume the
  232. # target user already has the necessary cookies
  233. sux_term=""
  234. sux_xauth_cmd=""
  235. sux_xauthority=""
  236. fi
  237. ##
  238. # Marshall the specified command in an effort to support parameters that
  239. # contain spaces. This should be enough to get commands like
  240. # 'xterm -title "My XTerm"' to work.
  241. sux_cmd=""
  242. if [ $# -gt 0 ]
  243. then
  244. while [ $# -gt 0 ]
  245. do
  246. sux_cmd="$sux_cmd \"$1\""
  247. shift
  248. done
  249. elif [ "`basename $0`" = "suxterm" ]
  250. then
  251. # Start an xterm, useful for temporary cookies
  252. sux_cmd="xterm"
  253. else
  254. # If no command is specified, start a shell
  255. if [ $# -eq 0 ]
  256. then
  257. if [ "$sux_got_minus" = "1" ]
  258. then
  259. sux_cmd="sh -c \"exec -l \$SHELL\""
  260. else
  261. sux_cmd="\$SHELL"
  262. fi
  263. fi
  264. fi
  265. ##
  266. # We would not want the other user to try and use our XAUTHORITY file. He
  267. # wouldn't have the proper access rights anyway...
  268. unset XAUTHORITY
  269. ##
  270. # --preserve-environment special case
  271. if [ -n "$sux_preserve" -a -n "$sux_xauth_cmd" ]
  272. then
  273. sux_home=`egrep "^$sux_username:" /etc/passwd | cut -d: -f6`
  274. if [ -z "$sux_home" ]
  275. then
  276. echo "WARNING: --preserve-environment has been set, but no good value was found for XAUTHORITY, expect trouble" >&2
  277. else
  278. export XAUTHORITY="$sux_home/.Xauthority"
  279. fi
  280. fi
  281. ##
  282. # Execute su
  283. exec su $sux_su_opts -c "$sux_xauth_cmd \
  284. exec env $sux_xauthority $sux_term DISPLAY='$DISPLAY' $sux_cmd;"