summaryrefslogtreecommitdiff
path: root/user-init
blob: 38ec924889c5a0d551a6e29463991cca637cce08 (plain)
  1. #!/bin/sh
  2. set -e
  3. # reset flags
  4. apache_reload_needed=""
  5. runmode="normal"
  6. # subfolder name defaults (edit /etc/local/users.conf to override)
  7. mac="mac" # Optimized for sharing through AppleShare (netatalk)
  8. pc="pc" # Optimized for sharing though SMB/CIFS (Samba)
  9. xchange="xchange" # Readable by group
  10. # config (edit /etc/local/users.conf to override)
  11. # which are user accounts (adduser values are used if empty)
  12. first_uid=""
  13. last_uid=""
  14. do_quota="no" # Manage disk quota
  15. do_distrib="no" # Distributed shares (software archive)
  16. do_personal="no" # Personal shares (mac, pc, public_html)
  17. do_xchange="no" # Group-readable shares
  18. do_public="no" # Public share (web homepage)
  19. do_mac="no" # AppleShare-optimized share (netatalk)
  20. do_pc="no" # SMB-ptimized share (Samba)
  21. do_server="no" # Personal share on remote SMB server
  22. quota_roots="" # space-delimited list of disk devices
  23. quota_soft="100000"
  24. quota_hard="1000000"
  25. quota_newstyle="yes" # Woody used a different syntax...
  26. xchange_root="xchange"
  27. xchange_sharedroot="/home/XCHANGE"
  28. mac_root="mac"
  29. pc_root="pc"
  30. server_name="SERVER" # SMB name of remote server
  31. server_desc="remote server"
  32. server_root="server"
  33. server_conf="/etc/security/pam_mount.conf"
  34. server_userconf=".winpassword"
  35. ### No servicable parts below this line! ###
  36. if [ -e /etc/adduser.conf ]; then
  37. . /etc/adduser.conf
  38. else
  39. echo "/etc/adduser.conf missing. Exiting..."
  40. exit 1
  41. fi
  42. [ -r /etc/local/users.conf ] && . /etc/local/users.conf
  43. #TODO: Add conversion like below, and change remaining script to new variable names
  44. #[ -n "$XDIR" ] && xchange_sharedroot="$XDIR"
  45. # exit silently if this system lacks required hints
  46. [ -r /etc/local/volumes ] && . /etc/local/volumes || exit 0
  47. XDIRREAL="$XDIR/users/root"
  48. if [ -n "$XCHANGE" ]; then
  49. if [ ! -d "$XDIR" ]; then
  50. echo "XDIR doesn't exist. Ignoring XCHANGE!"
  51. XCHANGE=""
  52. fi
  53. fi
  54. if [ $# -gt 0 ]; then
  55. USERS=$*
  56. else
  57. # USERS=`getent passwd | awk -F: '{print $1}'`
  58. echo "uid required!"
  59. exit 1
  60. fi
  61. [ -n "$NETATALK_HOME" ] && mac="$NETATALK_HOME"
  62. [ -n "$SAMBA_HOME" ] && pc="$SAMBA_HOME"
  63. [ -n "$XCHANGE_HOME" ] && xchange="$XCHANGE_HOME"
  64. echo "Setting up additional folders and permissions..."
  65. for user in $USERS; do
  66. uid="`getent passwd \"$user\" | awk -F: '{print $3}' | head -1`"
  67. HOME="`getent passwd \"$user\" | awk -F: '{print $6}' | head -1`"
  68. if [ -z "$HOME" ]; then
  69. echo "User $user doesn't exist. Ignoring..."
  70. continue
  71. fi
  72. # Ignore non-human accounts silently
  73. [ "$uid" -ge "$FIRST_UID" -a "$uid" -le "$LAST_UID" ] || continue
  74. [ -d "$HOME" ] || continue
  75. # [ -L "$HOME" ] && continue
  76. echo -n "$user"
  77. # if [ -x /etc/local/quota.sh ]; then
  78. # /etc/local/quota.sh "$user"
  79. # fi
  80. [ -n "$QUOTASOFT" ] || QUOTASOFT="0"
  81. [ -n "$QUOTAHARD" ] || QUOTAHARD="0"
  82. for QUOTAHOME in $QUOTAHOMES; do
  83. if [ -n "$NEW_QUOTA" ]; then
  84. setquota "$user" "$QUOTASOFT" "$QUOTAHARD" 0 0 "$QUOTAHOME"
  85. else
  86. setquota "$user" "$QUOTAHOME" "$QUOTASOFT" "$QUOTAHARD" 0 0
  87. fi
  88. done
  89. mkdir -p "$HOME/mail"
  90. if [ -n "$USE_MBOX" ]; then
  91. touch "$HOME/mail/mbox"
  92. elif [ -f "$HOME/mail/mbox" ] && [ ! -s "$HOME/mail/mbox" ]; then
  93. rm -f "$HOME/mail/mbox"
  94. fi
  95. if [ -n "$NETATALK" ]; then
  96. mkdir -p "$HOME/$mac"
  97. fi
  98. if [ -n "$SAMBA" ]; then
  99. mkdir -p "$HOME/$pc"
  100. fi
  101. if [ -n "$XCHANGE" ]; then
  102. mkdir -p "$XDIRREAL/$user"
  103. fi
  104. if [ -n "$PUBLIC" ]; then
  105. mkdir -p "$HOME/public_html"
  106. fi
  107. #TODO: Enable this only when option implemented to do it non-interactively
  108. # echo # dirty hack: better if being able to lower verbosity of localuserconfig
  109. # su -s /bin/bash -c localuserconfig "$user"
  110. if [ "$do_server" = "yes" ] && [ -r "$server_conf" ] && [ -f "$HOME/$server_userconf" ]; then
  111. server_username="$(grep '^username' \"$HOME/$server_userconf\" | awk -F= '{print $2}' | head -1 | awk '{print $1}')"
  112. if [ -n "$server_username" ]; then
  113. if grep -q "^volume $user " "$server_conf"; then
  114. perl -pi -e "s|^volume $user .*|volume $user smb $server_name $server_username $HOME/$server_root uid=$user,gid=$user - -|" "$server_conf"
  115. else
  116. echo "volume $user smb $server_name $server_username $HOME/$server_root uid=$user,gid=$user - -" >> "$server_conf"
  117. fi
  118. fi
  119. fi
  120. chown "$user": "$HOME"
  121. chmod u=rwX,go=rX "$HOME"
  122. # Mail handling
  123. chown -R "$user": "$HOME/mail"
  124. chmod -R u=rw,go=,u+X "$HOME/mail"
  125. if [ -f "$HOME/.mailboxlist" ]; then
  126. chown "$user": "$HOME/.mailboxlist"
  127. chmod 0640 "$HOME/.mailboxlist"
  128. fi
  129. if [ -f "$HOME/.forward" ]; then
  130. chown "$user": "$HOME/.forward"
  131. chmod 0640 "$HOME/.forward"
  132. fi
  133. if [ -f "/var/mail/$user" ]; then
  134. chown "$user":mail "/var/mail/$user"
  135. chmod ug=rw,o= "/var/mail/$user"
  136. elif [ -f "/var/spool/mail/$user" ]; then
  137. chown "$user":mail "/var/spool/mail/$user"
  138. chmod ug=rw,o= "/var/spool/mail/$user"
  139. fi
  140. # MySQL handling
  141. if [ -f "$HOME/.my.cnf" ]; then
  142. chown "$user": "$HOME/.my.cnf"
  143. chmod 0600 "$HOME/.my.cnf"
  144. fi
  145. # Mac dir permissions
  146. if [ -d "$HOME/$mac" ]; then
  147. chown -R "$user": "$HOME/$mac"
  148. chmod -R u=rw,g=r,o=,ug+X "$HOME/$mac"
  149. rm -rf "$HOME/$mac/Network Trash Folder"
  150. mkdir "$HOME/$mac/Network Trash Folder"
  151. chown nobody: "$HOME/$mac/Network Trash Folder"
  152. chmod a= "$HOME/$mac/Network Trash Folder"
  153. fi
  154. # PC dir permissions
  155. if [ -d "$HOME/$pc" ]; then
  156. chown -R "$user": "$HOME/$pc"
  157. chmod -R u=rw,g=r,o=,ug+X "$HOME/$pc"
  158. fi
  159. #FIXME: something is wrong with prefixing "x" here...
  160. # Exchange dir permissions
  161. if [ -d "$XDIRREAL/$user" ]; then
  162. chown -R "$user":users "$XDIRREAL/$user"
  163. chmod -R g=r,g+X "$XDIRREAL/$user"
  164. if [ -e "x$HOME/$xchange" ]; then
  165. if [ -L "x$HOME/$xchange" ]; then
  166. ln -sf "$XDIRREAL/$user $HOME/$xchange"
  167. else
  168. echo "ERROR: \"$HOME/$xchange\" exists already. Leaving it as is..."
  169. fi
  170. else
  171. ln -s "$XDIRREAL/$user" "$HOME/$xchange"
  172. fi
  173. fi
  174. # Public dir permissions
  175. if [ -d "$HOME/public_html" ]; then
  176. chown -R "$user": "$HOME/public_html"
  177. chmod -R u+rX,go=r,go+X "$HOME/public_html"
  178. if [ -n "$NETATALK" ]; then
  179. rm -rf "$HOME/public_html/Network Trash Folder"
  180. mkdir "$HOME/public_html/Network Trash Folder"
  181. chown nobody: "$HOME/public_html/Network Trash Folder"
  182. chmod a= "$HOME/public_html/Network Trash Folder"
  183. fi
  184. fi
  185. # Private dir permissions
  186. if [ -d "$HOME/private" ]; then
  187. chown -R "$user": "$HOME/private"
  188. chmod -R u+rX,g=r,g+X,o= "$HOME/private"
  189. fi
  190. # Fileshares: <home>/shares.<sharetype>/<rogroup>/<rwgroup>/<sharename>
  191. # <sharetype>: Either mac or win depending on which of netatalk and samba provides r/w access to the shares
  192. # <rwgroup>: Group with write access to the share (usually the default group of the owner)
  193. # <rogroup>: Either rwgroup or secondary group with read-only access to the share
  194. # owner and rwgroup members must be member of both groups
  195. find "$HOME" -mindepth 1 -maxdepth 1 -type d -print | egrep "^$HOME/shares\." | (while read thisdir; do
  196. sharetype="`basename \"$thisdir\" | awk -F. '{print $2}'`"
  197. # Define dir and file exceptions
  198. case "$sharetype" in
  199. mac)
  200. dirs_world_rw_create='.AppleDB'
  201. dirs_group_rw_create='.AppleDesktop/Temporary Items/TheFindByContentFolder'
  202. dirs_group_ro_create='TheVolumeSettingsFolder'
  203. dirs_group_ro_update='.AppleDouble'
  204. files_group_ro_update=':2eDS_Store'
  205. dirs_no_access_purge='Network Trash Folder'
  206. ;;
  207. win)
  208. ;;
  209. *)
  210. continue
  211. ;;
  212. esac
  213. exceptions="$dirs_world_rw_create/$dirs_group_rw_create/$dirs_group_ro_create/$dirs_group_ro_update/$files_group_ro_update/$dirs_no_access_purge"
  214. exception_dirs_create="$dirs_world_rw_create/$dirs_group_rw_create/$dirs_group_ro_create"
  215. chown "$user": "$thisdir"
  216. chmod a=rX "$thisdir"
  217. find "$thisdir" -mindepth 1 -maxdepth 1 -type d -print | (while read thisdir; do
  218. rogroup="`basename \"$thisdir\"`"
  219. chown "$user":"$rogroup" "$thisdir"
  220. chmod ug=rX,o= "$thisdir"
  221. find "$thisdir" -mindepth 1 -maxdepth 1 -type d -print | (while read thisdir; do
  222. rwgroup="`basename \"$thisdir\"`"
  223. chown "$user":"$rwgroup" "$thisdir"
  224. chmod a=rX,g+s "$thisdir"
  225. find "$thisdir" -mindepth 1 -maxdepth 1 -type d -print | (while read thisdir; do
  226. sharename="`basename \"$thisdir\"`"
  227. chown "$user":"$rwgroup" "$thisdir"
  228. chmod u=rw,go=r,a+X,g+s "$thisdir"
  229. ifs="$IFS"
  230. # Set default permissions
  231. find "$thisdir" -mindepth 1 -maxdepth 1 -print | (while read thisdir; do
  232. item="`basename \"$thisdir\"`"
  233. IFS="/"; for exception in $exceptions; do IFS="$ifs";
  234. if [ "$item" = "$exception" ]; then
  235. continue 2
  236. fi
  237. done
  238. chgrp -R "$rwgroup" "$thisdir"
  239. chmod -R ug=rw,o=r,a+X,g+s "$thisdir"
  240. done)
  241. # Handle exception dirs to be created if not existing
  242. IFS="/"; for dir in $exception_dirs_create; do IFS="$ifs";
  243. if [ ! -d "$thisdir/$dir" ]; then
  244. rm -f "$thisdir/$dir"
  245. fi
  246. if [ ! -e "$thisdir/$dir" ]; then
  247. mkdir "$thisdir/$dir"
  248. fi
  249. chown "$user":"$rwgroup" "$thisdir/$dir"
  250. done
  251. IFS="/"; for dir in $dirs_world_rw_create; do IFS="$ifs";
  252. if [ "$rogroup" = "$rwgroup" ]; then
  253. chmod -R ug=rw,o=r,a+X,g+s "$thisdir/$dir"
  254. else
  255. chmod -R a=rw,a+X,g+s "$thisdir/$dir"
  256. fi
  257. done
  258. IFS="/"; for dir in $dirs_group_rw_create; do IFS="$ifs";
  259. chmod -R ug=rw,o=r,a+X,g+s "$thisdir/$dir"
  260. done
  261. IFS="/"; for dir in $dirs_group_ro_create; do IFS="$ifs";
  262. chmod -R u=rw,go=r,a+X,g+s "$thisdir/$dir"
  263. done
  264. # Handle exception dirs to be updated if already there
  265. IFS="/"; for dir in $dirs_group_ro_update; do IFS="$ifs";
  266. if [ -e "$thisdir/$dir" ]; then
  267. chmod u=rw,go=r,a+X,g+s "$thisdir/$dir"
  268. fi
  269. done
  270. # Handle exception files to be updated if already there
  271. IFS="/"; for file in $files_group_ro_update; do IFS="$ifs";
  272. if [ -e "$thisdir/$file" ]; then
  273. chmod u=rw,go=r,g+s "$thisdir/$file"
  274. fi
  275. done
  276. # Handle exception dirs to be purged and recreated
  277. IFS="/"; for dir in $dirs_no_access_purge; do IFS="$ifs";
  278. rm -rf "$thisdir/$dir"
  279. mkdir -m a= "$thisdir/$dir"
  280. chown nobody: "$thisdir/$dir"
  281. done
  282. IFS="$ifs"
  283. done)
  284. done)
  285. done)
  286. done)
  287. # Deprecated share permissions
  288. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/shares_win"`; do
  289. chgrp -R "$user" "$dir"
  290. chmod -R u=rw,g=rw,o=,ug+X,g+s "$dir"
  291. done
  292. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/shares_mac"`; do
  293. chgrp -R "$user" "$dir"
  294. chmod -R u=rw,g=rw,o=,ug+X,g+s "$dir"
  295. rm -rf "$dir/Network Trash Folder"
  296. mkdir "$dir/Network Trash Folder"
  297. chown nobody: "$dir/Network Trash Folder"
  298. chmod a= "$dir/Network Trash Folder"
  299. done
  300. # Ftp shares permissions
  301. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/ftp_$USER$"`; do
  302. chgrp -R "$user" "$dir"
  303. chmod -R ug=rw,o=r,a+X,g+s "$dir"
  304. rm -rf "$dir/Network Trash Folder"
  305. mkdir "$dir/Network Trash Folder"
  306. chown nobody: "$dir/Network Trash Folder"
  307. chmod a= "$dir/Network Trash Folder"
  308. done
  309. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/ftp_${USER}_ro$"`; do
  310. chown -R "$user": "$dir"
  311. chmod -R u=rw,go=r,a+X "$dir"
  312. rm -rf "$dir/Network Trash Folder"
  313. mkdir "$dir/Network Trash Folder"
  314. chown nobody: "$dir/Network Trash Folder"
  315. chmod a= "$dir/Network Trash Folder"
  316. done
  317. # Web shares permissions
  318. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/web_"`; do
  319. chown -R "$user": "$dir"
  320. # chmod -R u=rw,go=r,a+X $webdir
  321. #TODO: Only cgi scripts (.cgi and .pl) should be executable
  322. chmod -R u+rw,go+r,a+X "$dir"
  323. # leftover from ancient times with another policy
  324. if [ $NETATALK ]; then
  325. rm -rf "$dir/Network Trash Folder"
  326. fi
  327. done
  328. # Web shares permissions
  329. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/websites"`; do
  330. chown root: "$dir"
  331. chmod a=r,u+w,a+X "$dir"
  332. done
  333. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/websites/"`; do
  334. chown -R "$user": "$dir"
  335. # chmod -R u=rw,go=r,a+X $webdir
  336. #TODO: Only cgi scripts (.cgi and .pl) should be executable
  337. chmod -R u+rw,go+r,a+X "$dir"
  338. # leftover from ancient times with another policy
  339. if [ $NETATALK ]; then
  340. rm -rf "$dir/Network Trash Folder"
  341. fi
  342. done
  343. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webscripts"`; do
  344. chown root: "$dir"
  345. chmod a=r,u+w,a+X "$dir"
  346. done
  347. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webscripts/"`; do
  348. chown -R $user: "$dir"
  349. # chmod -R u=rw,go=r,a+X $webdir
  350. #TODO: Only cgi scripts (.cgi and .pl) should be executable
  351. chmod -R u+rw,go+r,a+X "$dir"
  352. done
  353. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webdata"`; do
  354. chown "$user": "$dir"
  355. chmod a=r,u+w,a+X "$dir"
  356. done
  357. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webdata/"`; do
  358. chown -R "$user": "$dir"
  359. chmod -R u=rw,go=,u+X "$dir"
  360. done
  361. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webshareddata"`; do
  362. chown "$user": "$dir"
  363. chmod a=r,u+w,a+X "$dir"
  364. done
  365. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webshareddata/"`; do
  366. chown -R "$user:" "$dir"
  367. chmod -R u=rw,go=r,a+X "$dir"
  368. done
  369. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webphpsites"`; do
  370. chown root: "$dir"
  371. chmod u=rw,go=r,a+X "$dir"
  372. done
  373. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webphpsites/"`; do
  374. chown -R "$user":www-data "$dir"
  375. # chmod -R ug=rw,o=r,a+X $dir
  376. chmod -R ug=rw,o=,ug+X "$dir"
  377. done
  378. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webphpdata"`; do
  379. chown root: "$dir"
  380. chmod a=r,u+w,a+X "$dir"
  381. done
  382. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webphpdata/"`; do
  383. chown -R "$user":www-data "$dir"
  384. chmod -R ug=rw,o=,ug+X "$dir"
  385. done
  386. # Dummy user restrictions
  387. if [ -n "$REALUSERS_GROUPNAME" -a -n "$DUMMYSHAREDIR" -a -n "$DUMMYSHAREOWNER" -a -n "$DUMMYSHARENAME" ]; then
  388. [ -e $DUMMYSHAREDIR/$user ] \
  389. || mkdir $DUMMYSHAREDIR/$user
  390. chown $DUMMYSHAREOWNER: $DUMMYSHAREDIR/$user
  391. chmod u=rw,go=r,a+X $DUMMYSHAREDIR/$user
  392. if [ -e $HOME/$DUMMYSHARENAME ]; then
  393. if [ -L $HOME/$DUMMYSHARENAME ]; then
  394. ln -sf $DUMMYSHAREDIR/$user $HOME/$DUMMYSHARENAME
  395. chown $user: $HOME/$DUMMYSHARENAME
  396. else
  397. echo "WARNING: $HOME/$DUMMYSHAREDIR exists already. Leaving it as is..."
  398. fi
  399. else
  400. ln -s $DUMMYSHAREDIR/$user $HOME/$DUMMYSHARENAME
  401. chown $user: $HOME/$DUMMYSHARENAME
  402. fi
  403. if [ -n "$DUMMYAPACHECFG" -a -n "$DUMMYAPACHESHAREDIR" ]; then
  404. if [ -f /etc/apache/include.d/$DUMMYAPACHECFG -a -x /etc/init.d/apache ]; then
  405. if [ -e /etc/apache/include.d/$DUMMYAPACHECFG-$user ]; then
  406. echo "/etc/apache/include.d/$DUMMYAPACHECFG-$user exists already. Ignoring..."
  407. else
  408. echo "# Created automatically by adduser.local
  409. <Location /$DUMMYAPACHESHAREDIR/$user>
  410. <Limit GET POST>
  411. require user $user
  412. </Limit>
  413. </Location>" \
  414. > /etc/apache/include.d/$DUMMYAPACHECFG-$user
  415. apache_reload_needed="1"
  416. fi
  417. fi
  418. fi
  419. fi
  420. echo "."
  421. done
  422. if [ $XCHANGE ]; then
  423. for USER in $(ls $XDIRREAL); do
  424. id $user >/dev/null 2>&1 || rm -rf $XDIRREAL/$user
  425. done
  426. fi
  427. if [ "$apache_reload_needed" ]; then
  428. apache_do_reload=""
  429. case runmode in
  430. interactive)
  431. echo -n "Apache config changed. Reload Apache now (Y/n)? "
  432. read apache_reload
  433. case $apache_reload in
  434. y|Y|"")
  435. apache_do_reload="1"
  436. ;;
  437. esac
  438. ;;
  439. force)
  440. apache_do_reload="1"
  441. ;;
  442. *)
  443. echo "Apache config has changed. Remember to reload Apache...!"
  444. ;;
  445. esac
  446. if "$apache_do_reload" ]; then
  447. /etc/init.d/apache force-reload
  448. fi
  449. fi