summaryrefslogtreecommitdiff
path: root/user-init
blob: 18e5675d03dd9ee91fddd913e85791d56f1ed509 (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. [ $QUOTASOFT ] || QUOTASOFT="0"
  81. [ $QUOTAHARD ] || QUOTAHARD="0"
  82. for QUOTAHOME in $QUOTAHOMES; do
  83. if [ $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 [ "$USE_MBOX" ]; then
  91. touch $HOME/mail/mbox
  92. elif [ -f $HOME/mail/mbox -a ! -s $HOME/mail/mbox ]; then
  93. rm -f $HOME/mail/mbox
  94. fi
  95. if [ $NETATALK ]; then
  96. mkdir -p $HOME/$mac
  97. fi
  98. if [ $SAMBA ]; then
  99. mkdir -p $HOME/$pc
  100. fi
  101. if [ $XCHANGE ]; then
  102. mkdir -p $XDIRREAL/$user
  103. fi
  104. if [ $PUBLIC ]; then
  105. mkdir -p $HOME/public_html
  106. fi
  107. #TODO: Convert the above syntax to the below...
  108. if [ "$do_server" = "yes" ]; then
  109. mkdir -p $HOME/"$server_root"
  110. # chown root: $HOME/"$server_root"
  111. # chmod 0444 $HOME/"$server_root"
  112. # touch $HOME/"$server_root"/NOT_MOUNTED
  113. # chown root: $HOME/"$server_root"NOT_MOUNTED
  114. # chmod 0444 $HOME/"$server_root"/NOT_MOUNTED
  115. #TODO: figure out a safe way to do the above (avoid if mounted, for example!)
  116. fi
  117. #TODO: Move dir creation to localuserconfig, to respect user removing custom dirs
  118. su -s /bin/bash -c localuserconfig $user
  119. if [ "$do_server" = "yes" -a -r "$server_conf" -a -r $HOME/"$server_userconf" ]; then
  120. server_username="$(grep '^username' $HOME/$server_userconf | awk -F= '{print $2}' | head -1 | awk '{print $1}')"
  121. if grep -q "^volume $user " "$server_conf"; then
  122. perl -pi -e "s|^volume $user .*|volume $user smb $server_name $server_username $HOME/$server_root uid=$user,gid=$user - -|" "$server_conf"
  123. else
  124. echo "volume $user smb $server_name $server_username $HOME/$server_root uid=$user,gid=$user - -" >> "$server_conf"
  125. fi
  126. fi
  127. exit 1
  128. chown $user: $HOME
  129. chmod u=rwX,go=rX $HOME
  130. # Mail handling
  131. chown -R $user: $HOME/mail
  132. chmod -R u=rw,go=,u+X $HOME/mail
  133. if [ -f $HOME/.mailboxlist ]; then
  134. chown $user: $HOME/.mailboxlist
  135. chmod 0640 $HOME/.mailboxlist
  136. fi
  137. if [ -f $HOME/.forward ]; then
  138. chown $user: $HOME/.forward
  139. chmod 0640 $HOME/.forward
  140. fi
  141. if [ -f /var/mail/$user ]; then
  142. chown $user:mail /var/mail/$user
  143. chmod ug=rw,o= /var/mail/$user
  144. elif [ -f /var/spool/mail/$user ]; then
  145. chown $user:mail /var/spool/mail/$user
  146. chmod ug=rw,o= /var/spool/mail/$user
  147. fi
  148. # MySQL handling
  149. if [ -f $HOME/.my.cnf ]; then
  150. chown $user: $HOME/.my.cnf
  151. chmod 0600 $HOME/.my.cnf
  152. fi
  153. # Mac dir permissions
  154. if [ -d $HOME/$mac ]; then
  155. chown -R $user: $HOME/$mac
  156. chmod -R u=rw,g=r,o=,ug+X $HOME/$mac
  157. rm -rf $HOME/$mac/Network\ Trash\ Folder
  158. mkdir $HOME/$mac/Network\ Trash\ Folder
  159. chown nobody: $HOME/$mac/Network\ Trash\ Folder
  160. chmod a= $HOME/$mac/Network\ Trash\ Folder
  161. fi
  162. # PC dir permissions
  163. if [ -d $HOME/$pc ]; then
  164. chown -R $user: $HOME/$pc
  165. chmod -R u=rw,g=r,o=,ug+X $HOME/$pc
  166. fi
  167. # Exchange dir permissions
  168. if [ -d $XDIRREAL/$user ]; then
  169. chown -R $user:users $XDIRREAL/$user
  170. chmod -R g=r,g+X $XDIRREAL/$user
  171. if [ -e "x$HOME/$xchange" ]; then
  172. if [ -L "x$HOME/$xchange" ]; then
  173. ln -sf $XDIRREAL/$user $HOME/$xchange
  174. else
  175. echo "ERROR: $HOME/$xchange exists already. Leaving it as is..."
  176. fi
  177. else
  178. ln -s $XDIRREAL/$user $HOME/$xchange
  179. fi
  180. fi
  181. # Public dir permissions
  182. if [ -d $HOME/public_html ]; then
  183. chown -R $user: $HOME/public_html
  184. chmod -R u+rX,go=r,go+X $HOME/public_html
  185. if [ $NETATALK ]; then
  186. rm -rf $HOME/public_html/Network\ Trash\ Folder
  187. mkdir $HOME/public_html/Network\ Trash\ Folder
  188. chown nobody: $HOME/public_html/Network\ Trash\ Folder
  189. chmod a= $HOME/public_html/Network\ Trash\ Folder
  190. fi
  191. fi
  192. # Fileshares: <home>/shares.<sharetype>/<rogroup>/<rwgroup>/<sharename>
  193. # <sharetype>: Either mac or win depending on which of netatalk and samba provides r/w access to the shares
  194. # <rwgroup>: Group with write access to the share (usually the default group of the owner)
  195. # <rogroup>: Either rwgroup or secondary group with read-only access to the share
  196. # owner and rwgroup members must be member of both groups
  197. find "$HOME" -mindepth 1 -maxdepth 1 -type d -print | egrep "^$HOME/shares\." | (while read thisdir; do
  198. sharetype="`basename \"$thisdir\" | awk -F. '{print $2}'`"
  199. # Define dir and file exceptions
  200. case "$sharetype" in
  201. mac)
  202. dirs_world_rw_create='.AppleDB'
  203. dirs_group_rw_create='.AppleDesktop/Temporary Items/TheFindByContentFolder'
  204. dirs_group_ro_create='TheVolumeSettingsFolder'
  205. dirs_group_ro_update='.AppleDouble'
  206. files_group_ro_update=':2eDS_Store'
  207. dirs_no_access_purge='Network Trash Folder'
  208. ;;
  209. win)
  210. ;;
  211. *)
  212. continue
  213. ;;
  214. esac
  215. 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"
  216. exception_dirs_create="$dirs_world_rw_create/$dirs_group_rw_create/$dirs_group_ro_create"
  217. chown "$user": "$thisdir"
  218. chmod a=rX "$thisdir"
  219. find "$thisdir" -mindepth 1 -maxdepth 1 -type d -print | (while read thisdir; do
  220. rogroup="`basename \"$thisdir\"`"
  221. chown "$user":"$rogroup" "$thisdir"
  222. chmod ug=rX,o= "$thisdir"
  223. find "$thisdir" -mindepth 1 -maxdepth 1 -type d -print | (while read thisdir; do
  224. rwgroup="`basename \"$thisdir\"`"
  225. chown "$user":"$rwgroup" "$thisdir"
  226. chmod a=rX,g+s "$thisdir"
  227. find "$thisdir" -mindepth 1 -maxdepth 1 -type d -print | (while read thisdir; do
  228. sharename="`basename \"$thisdir\"`"
  229. chown "$user":"$rwgroup" "$thisdir"
  230. chmod u=rw,go=r,a+X,g+s "$thisdir"
  231. ifs="$IFS"
  232. # Set default permissions
  233. find "$thisdir" -mindepth 1 -maxdepth 1 -print | (while read thisdir; do
  234. item="`basename \"$thisdir\"`"
  235. IFS="/"; for exception in $exceptions; do IFS="$ifs";
  236. if [ "$item" = "$exception" ]; then
  237. continue 2
  238. fi
  239. done
  240. chgrp -R "$rwgroup" "$thisdir"
  241. chmod -R ug=rw,o=r,a+X,g+s "$thisdir"
  242. done)
  243. # Handle exception dirs to be created if not existing
  244. IFS="/"; for dir in $exception_dirs_create; do IFS="$ifs";
  245. if [ ! -d "$thisdir/$dir" ]; then
  246. rm -f "$thisdir/$dir"
  247. fi
  248. if [ ! -e "$thisdir/$dir" ]; then
  249. mkdir "$thisdir/$dir"
  250. fi
  251. chown "$user":"$rwgroup" "$thisdir/$dir"
  252. done
  253. IFS="/"; for dir in $dirs_world_rw_create; do IFS="$ifs";
  254. if [ "$rogroup" = "$rwgroup" ]; then
  255. chmod -R ug=rw,o=r,a+X,g+s "$thisdir/$dir"
  256. else
  257. chmod -R a=rw,a+X,g+s "$thisdir/$dir"
  258. fi
  259. done
  260. IFS="/"; for dir in $dirs_group_rw_create; do IFS="$ifs";
  261. chmod -R ug=rw,o=r,a+X,g+s "$thisdir/$dir"
  262. done
  263. IFS="/"; for dir in $dirs_group_ro_create; do IFS="$ifs";
  264. chmod -R u=rw,go=r,a+X,g+s "$thisdir/$dir"
  265. done
  266. # Handle exception dirs to be updated if already there
  267. IFS="/"; for dir in $dirs_group_ro_update; do IFS="$ifs";
  268. if [ -e "$thisdir/$dir" ]; then
  269. chmod u=rw,go=r,a+X,g+s "$thisdir/$dir"
  270. fi
  271. done
  272. # Handle exception files to be updated if already there
  273. IFS="/"; for file in $files_group_ro_update; do IFS="$ifs";
  274. if [ -e "$thisdir/$file" ]; then
  275. chmod u=rw,go=r,g+s "$thisdir/$file"
  276. fi
  277. done
  278. # Handle exception dirs to be purged and recreated
  279. IFS="/"; for dir in $dirs_no_access_purge; do IFS="$ifs";
  280. rm -rf "$thisdir/$dir"
  281. mkdir -m a= "$thisdir/$dir"
  282. chown nobody: "$thisdir/$dir"
  283. done
  284. IFS="$ifs"
  285. done)
  286. done)
  287. done)
  288. done)
  289. # Deprecated share permissions
  290. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/shares_win"`; do
  291. chgrp -R $user $dir
  292. chmod -R u=rw,g=rw,o=,ug+X,g+s $dir
  293. done
  294. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/shares_mac"`; do
  295. chgrp -R $user $dir
  296. chmod -R u=rw,g=rw,o=,ug+X,g+s $dir
  297. rm -rf $dir/Network\ Trash\ Folder
  298. mkdir $dir/Network\ Trash\ Folder
  299. chown nobody: $dir/Network\ Trash\ Folder
  300. chmod a= $dir/Network\ Trash\ Folder
  301. done
  302. # Ftp shares permissions
  303. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/ftp_$USER$"`; do
  304. chgrp -R $user $dir
  305. chmod -R ug=rw,o=r,a+X,g+s $dir
  306. rm -rf $dir/Network\ Trash\ Folder
  307. mkdir $dir/Network\ Trash\ Folder
  308. chown nobody: $dir/Network\ Trash\ Folder
  309. chmod a= $dir/Network\ Trash\ Folder
  310. done
  311. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/ftp_${USER}_ro$"`; do
  312. chown -R $user: $dir
  313. chmod -R u=rw,go=r,a+X $dir
  314. rm -rf $dir/Network\ Trash\ Folder
  315. mkdir $dir/Network\ Trash\ Folder
  316. chown nobody: $dir/Network\ Trash\ Folder
  317. chmod a= $dir/Network\ Trash\ Folder
  318. done
  319. # Web shares permissions
  320. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/web_"`; do
  321. chown -R $user: $dir
  322. # chmod -R u=rw,go=r,a+X $webdir
  323. #TODO: Only cgi scripts (.cgi and .pl) should be executable
  324. chmod -R u+rw,go+r,a+X $dir
  325. # leftover from ancient times with another policy
  326. if [ $NETATALK ]; then
  327. rm -rf $dir/Network\ Trash\ Folder
  328. fi
  329. done
  330. # Web shares permissions
  331. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/websites"`; do
  332. chown root: $dir
  333. chmod a=r,u+w,a+X $dir
  334. done
  335. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/websites/"`; do
  336. chown -R $user: $dir
  337. # chmod -R u=rw,go=r,a+X $webdir
  338. #TODO: Only cgi scripts (.cgi and .pl) should be executable
  339. chmod -R u+rw,go+r,a+X $dir
  340. # leftover from ancient times with another policy
  341. if [ $NETATALK ]; then
  342. rm -rf $dir/Network\ Trash\ Folder
  343. fi
  344. done
  345. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webscripts"`; do
  346. chown root: $dir
  347. chmod a=r,u+w,a+X $dir
  348. done
  349. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webscripts/"`; do
  350. chown -R $user: $dir
  351. # chmod -R u=rw,go=r,a+X $webdir
  352. #TODO: Only cgi scripts (.cgi and .pl) should be executable
  353. chmod -R u+rw,go+r,a+X $dir
  354. done
  355. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webdata"`; do
  356. chown $user: $dir
  357. chmod a=r,u+w,a+X $dir
  358. done
  359. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webdata/"`; do
  360. chown -R $user: $dir
  361. chmod -R u=rw,go=,u+X $dir
  362. done
  363. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webshareddata"`; do
  364. chown $user: $dir
  365. chmod a=r,u+w,a+X $dir
  366. done
  367. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webshareddata/"`; do
  368. chown -R $user: $dir
  369. chmod -R u=rw,go=r,a+X $dir
  370. done
  371. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webphpsites"`; do
  372. chown root: $dir
  373. chmod u=rw,go=r,a+X $dir
  374. done
  375. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webphpsites/"`; do
  376. chown -R $user:www-data $dir
  377. # chmod -R ug=rw,o=r,a+X $dir
  378. chmod -R ug=rw,o=,ug+X $dir
  379. done
  380. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webphpdata"`; do
  381. chown root: $dir
  382. chmod a=r,u+w,a+X $dir
  383. done
  384. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webphpdata/"`; do
  385. chown -R $user:www-data $dir
  386. chmod -R ug=rw,o=,ug+X $dir
  387. done
  388. # Dummy user restrictions
  389. if [ -n "$REALUSERS_GROUPNAME" -a -n "$DUMMYSHAREDIR" -a -n "$DUMMYSHAREOWNER" -a -n "$DUMMYSHARENAME" ]; then
  390. [ -e $DUMMYSHAREDIR/$user ] \
  391. || mkdir $DUMMYSHAREDIR/$user
  392. chown $DUMMYSHAREOWNER: $DUMMYSHAREDIR/$user
  393. chmod u=rw,go=r,a+X $DUMMYSHAREDIR/$user
  394. if [ -e $HOME/$DUMMYSHARENAME ]; then
  395. if [ -L $HOME/$DUMMYSHARENAME ]; then
  396. ln -sf $DUMMYSHAREDIR/$user $HOME/$DUMMYSHARENAME
  397. chown $user: $HOME/$DUMMYSHARENAME
  398. else
  399. echo "WARNING: $HOME/$DUMMYSHAREDIR exists already. Leaving it as is..."
  400. fi
  401. else
  402. ln -s $DUMMYSHAREDIR/$user $HOME/$DUMMYSHARENAME
  403. chown $user: $HOME/$DUMMYSHARENAME
  404. fi
  405. if [ -n "$DUMMYAPACHECFG" -a -n "$DUMMYAPACHESHAREDIR" ]; then
  406. if [ -f /etc/apache/include.d/$DUMMYAPACHECFG -a -x /etc/init.d/apache ]; then
  407. if [ -e /etc/apache/include.d/$DUMMYAPACHECFG-$user ]; then
  408. echo "/etc/apache/include.d/$DUMMYAPACHECFG-$user exists already. Ignoring..."
  409. else
  410. echo "# Created automatically by adduser.local
  411. <Location /$DUMMYAPACHESHAREDIR/$user>
  412. <Limit GET POST>
  413. require user $user
  414. </Limit>
  415. </Location>" \
  416. > /etc/apache/include.d/$DUMMYAPACHECFG-$user
  417. apache_reload_needed="1"
  418. fi
  419. fi
  420. fi
  421. fi
  422. echo "."
  423. done
  424. if [ $XCHANGE ]; then
  425. for USER in $(ls $XDIRREAL); do
  426. id $user >/dev/null 2>&1 || rm -rf $XDIRREAL/$user
  427. done
  428. fi
  429. if [ "$apache_reload_needed" ]; then
  430. apache_do_reload=""
  431. case runmode in
  432. interactive)
  433. echo -n "Apache config changed. Reload Apache now (Y/n)? "
  434. read apache_reload
  435. case $apache_reload in
  436. y|Y|"")
  437. apache_do_reload="1"
  438. ;;
  439. esac
  440. ;;
  441. force)
  442. apache_do_reload="1"
  443. ;;
  444. *)
  445. echo "Apache config has changed. Remember to reload Apache...!"
  446. ;;
  447. esac
  448. if "$apache_do_reload" ]; then
  449. /etc/init.d/apache force-reload
  450. fi
  451. fi