summaryrefslogtreecommitdiff
path: root/user-init
blob: 6a7218e3eae7f3625818d5fb58fc7732f6569df5 (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: 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" -a -r "$server_conf" -a -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. # Exchange dir permissions
  160. if [ -d $XDIRREAL/$user ]; then
  161. chown -R $user:users $XDIRREAL/$user
  162. chmod -R g=r,g+X $XDIRREAL/$user
  163. if [ -e "x$HOME/$xchange" ]; then
  164. if [ -L "x$HOME/$xchange" ]; then
  165. ln -sf $XDIRREAL/$user $HOME/$xchange
  166. else
  167. echo "ERROR: $HOME/$xchange exists already. Leaving it as is..."
  168. fi
  169. else
  170. ln -s $XDIRREAL/$user $HOME/$xchange
  171. fi
  172. fi
  173. # Public dir permissions
  174. if [ -d $HOME/public_html ]; then
  175. chown -R $user: $HOME/public_html
  176. chmod -R u+rX,go=r,go+X $HOME/public_html
  177. if [ $NETATALK ]; then
  178. rm -rf $HOME/public_html/Network\ Trash\ Folder
  179. mkdir $HOME/public_html/Network\ Trash\ Folder
  180. chown nobody: $HOME/public_html/Network\ Trash\ Folder
  181. chmod a= $HOME/public_html/Network\ Trash\ Folder
  182. fi
  183. fi
  184. # Fileshares: <home>/shares.<sharetype>/<rogroup>/<rwgroup>/<sharename>
  185. # <sharetype>: Either mac or win depending on which of netatalk and samba provides r/w access to the shares
  186. # <rwgroup>: Group with write access to the share (usually the default group of the owner)
  187. # <rogroup>: Either rwgroup or secondary group with read-only access to the share
  188. # owner and rwgroup members must be member of both groups
  189. find "$HOME" -mindepth 1 -maxdepth 1 -type d -print | egrep "^$HOME/shares\." | (while read thisdir; do
  190. sharetype="`basename \"$thisdir\" | awk -F. '{print $2}'`"
  191. # Define dir and file exceptions
  192. case "$sharetype" in
  193. mac)
  194. dirs_world_rw_create='.AppleDB'
  195. dirs_group_rw_create='.AppleDesktop/Temporary Items/TheFindByContentFolder'
  196. dirs_group_ro_create='TheVolumeSettingsFolder'
  197. dirs_group_ro_update='.AppleDouble'
  198. files_group_ro_update=':2eDS_Store'
  199. dirs_no_access_purge='Network Trash Folder'
  200. ;;
  201. win)
  202. ;;
  203. *)
  204. continue
  205. ;;
  206. esac
  207. 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"
  208. exception_dirs_create="$dirs_world_rw_create/$dirs_group_rw_create/$dirs_group_ro_create"
  209. chown "$user": "$thisdir"
  210. chmod a=rX "$thisdir"
  211. find "$thisdir" -mindepth 1 -maxdepth 1 -type d -print | (while read thisdir; do
  212. rogroup="`basename \"$thisdir\"`"
  213. chown "$user":"$rogroup" "$thisdir"
  214. chmod ug=rX,o= "$thisdir"
  215. find "$thisdir" -mindepth 1 -maxdepth 1 -type d -print | (while read thisdir; do
  216. rwgroup="`basename \"$thisdir\"`"
  217. chown "$user":"$rwgroup" "$thisdir"
  218. chmod a=rX,g+s "$thisdir"
  219. find "$thisdir" -mindepth 1 -maxdepth 1 -type d -print | (while read thisdir; do
  220. sharename="`basename \"$thisdir\"`"
  221. chown "$user":"$rwgroup" "$thisdir"
  222. chmod u=rw,go=r,a+X,g+s "$thisdir"
  223. ifs="$IFS"
  224. # Set default permissions
  225. find "$thisdir" -mindepth 1 -maxdepth 1 -print | (while read thisdir; do
  226. item="`basename \"$thisdir\"`"
  227. IFS="/"; for exception in $exceptions; do IFS="$ifs";
  228. if [ "$item" = "$exception" ]; then
  229. continue 2
  230. fi
  231. done
  232. chgrp -R "$rwgroup" "$thisdir"
  233. chmod -R ug=rw,o=r,a+X,g+s "$thisdir"
  234. done)
  235. # Handle exception dirs to be created if not existing
  236. IFS="/"; for dir in $exception_dirs_create; do IFS="$ifs";
  237. if [ ! -d "$thisdir/$dir" ]; then
  238. rm -f "$thisdir/$dir"
  239. fi
  240. if [ ! -e "$thisdir/$dir" ]; then
  241. mkdir "$thisdir/$dir"
  242. fi
  243. chown "$user":"$rwgroup" "$thisdir/$dir"
  244. done
  245. IFS="/"; for dir in $dirs_world_rw_create; do IFS="$ifs";
  246. if [ "$rogroup" = "$rwgroup" ]; then
  247. chmod -R ug=rw,o=r,a+X,g+s "$thisdir/$dir"
  248. else
  249. chmod -R a=rw,a+X,g+s "$thisdir/$dir"
  250. fi
  251. done
  252. IFS="/"; for dir in $dirs_group_rw_create; do IFS="$ifs";
  253. chmod -R ug=rw,o=r,a+X,g+s "$thisdir/$dir"
  254. done
  255. IFS="/"; for dir in $dirs_group_ro_create; do IFS="$ifs";
  256. chmod -R u=rw,go=r,a+X,g+s "$thisdir/$dir"
  257. done
  258. # Handle exception dirs to be updated if already there
  259. IFS="/"; for dir in $dirs_group_ro_update; do IFS="$ifs";
  260. if [ -e "$thisdir/$dir" ]; then
  261. chmod u=rw,go=r,a+X,g+s "$thisdir/$dir"
  262. fi
  263. done
  264. # Handle exception files to be updated if already there
  265. IFS="/"; for file in $files_group_ro_update; do IFS="$ifs";
  266. if [ -e "$thisdir/$file" ]; then
  267. chmod u=rw,go=r,g+s "$thisdir/$file"
  268. fi
  269. done
  270. # Handle exception dirs to be purged and recreated
  271. IFS="/"; for dir in $dirs_no_access_purge; do IFS="$ifs";
  272. rm -rf "$thisdir/$dir"
  273. mkdir -m a= "$thisdir/$dir"
  274. chown nobody: "$thisdir/$dir"
  275. done
  276. IFS="$ifs"
  277. done)
  278. done)
  279. done)
  280. done)
  281. # Deprecated share permissions
  282. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/shares_win"`; do
  283. chgrp -R $user $dir
  284. chmod -R u=rw,g=rw,o=,ug+X,g+s $dir
  285. done
  286. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/shares_mac"`; do
  287. chgrp -R $user $dir
  288. chmod -R u=rw,g=rw,o=,ug+X,g+s $dir
  289. rm -rf $dir/Network\ Trash\ Folder
  290. mkdir $dir/Network\ Trash\ Folder
  291. chown nobody: $dir/Network\ Trash\ Folder
  292. chmod a= $dir/Network\ Trash\ Folder
  293. done
  294. # Ftp shares permissions
  295. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/ftp_$USER$"`; do
  296. chgrp -R $user $dir
  297. chmod -R ug=rw,o=r,a+X,g+s $dir
  298. rm -rf $dir/Network\ Trash\ Folder
  299. mkdir $dir/Network\ Trash\ Folder
  300. chown nobody: $dir/Network\ Trash\ Folder
  301. chmod a= $dir/Network\ Trash\ Folder
  302. done
  303. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/ftp_${USER}_ro$"`; do
  304. chown -R $user: $dir
  305. chmod -R u=rw,go=r,a+X $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. # Web shares permissions
  312. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/web_"`; do
  313. chown -R $user: $dir
  314. # chmod -R u=rw,go=r,a+X $webdir
  315. #TODO: Only cgi scripts (.cgi and .pl) should be executable
  316. chmod -R u+rw,go+r,a+X $dir
  317. # leftover from ancient times with another policy
  318. if [ $NETATALK ]; then
  319. rm -rf $dir/Network\ Trash\ Folder
  320. fi
  321. done
  322. # Web shares permissions
  323. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/websites"`; do
  324. chown root: $dir
  325. chmod a=r,u+w,a+X $dir
  326. done
  327. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/websites/"`; do
  328. chown -R $user: $dir
  329. # chmod -R u=rw,go=r,a+X $webdir
  330. #TODO: Only cgi scripts (.cgi and .pl) should be executable
  331. chmod -R u+rw,go+r,a+X $dir
  332. # leftover from ancient times with another policy
  333. if [ $NETATALK ]; then
  334. rm -rf $dir/Network\ Trash\ Folder
  335. fi
  336. done
  337. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webscripts"`; do
  338. chown root: $dir
  339. chmod a=r,u+w,a+X $dir
  340. done
  341. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webscripts/"`; do
  342. chown -R $user: $dir
  343. # chmod -R u=rw,go=r,a+X $webdir
  344. #TODO: Only cgi scripts (.cgi and .pl) should be executable
  345. chmod -R u+rw,go+r,a+X $dir
  346. done
  347. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webdata"`; do
  348. chown $user: $dir
  349. chmod a=r,u+w,a+X $dir
  350. done
  351. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webdata/"`; do
  352. chown -R $user: $dir
  353. chmod -R u=rw,go=,u+X $dir
  354. done
  355. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webshareddata"`; 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/webshareddata/"`; do
  360. chown -R $user: $dir
  361. chmod -R u=rw,go=r,a+X $dir
  362. done
  363. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webphpsites"`; do
  364. chown root: $dir
  365. chmod u=rw,go=r,a+X $dir
  366. done
  367. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webphpsites/"`; do
  368. chown -R $user:www-data $dir
  369. # chmod -R ug=rw,o=r,a+X $dir
  370. chmod -R ug=rw,o=,ug+X $dir
  371. done
  372. for dir in `find $HOME -mindepth 1 -maxdepth 1 -type d | egrep "^$HOME/webphpdata"`; do
  373. chown root: $dir
  374. chmod a=r,u+w,a+X $dir
  375. done
  376. for dir in `find $HOME -mindepth 2 -maxdepth 2 -type d | egrep "^$HOME/webphpdata/"`; do
  377. chown -R $user:www-data $dir
  378. chmod -R ug=rw,o=,ug+X $dir
  379. done
  380. # Dummy user restrictions
  381. if [ -n "$REALUSERS_GROUPNAME" -a -n "$DUMMYSHAREDIR" -a -n "$DUMMYSHAREOWNER" -a -n "$DUMMYSHARENAME" ]; then
  382. [ -e $DUMMYSHAREDIR/$user ] \
  383. || mkdir $DUMMYSHAREDIR/$user
  384. chown $DUMMYSHAREOWNER: $DUMMYSHAREDIR/$user
  385. chmod u=rw,go=r,a+X $DUMMYSHAREDIR/$user
  386. if [ -e $HOME/$DUMMYSHARENAME ]; then
  387. if [ -L $HOME/$DUMMYSHARENAME ]; then
  388. ln -sf $DUMMYSHAREDIR/$user $HOME/$DUMMYSHARENAME
  389. chown $user: $HOME/$DUMMYSHARENAME
  390. else
  391. echo "WARNING: $HOME/$DUMMYSHAREDIR exists already. Leaving it as is..."
  392. fi
  393. else
  394. ln -s $DUMMYSHAREDIR/$user $HOME/$DUMMYSHARENAME
  395. chown $user: $HOME/$DUMMYSHARENAME
  396. fi
  397. if [ -n "$DUMMYAPACHECFG" -a -n "$DUMMYAPACHESHAREDIR" ]; then
  398. if [ -f /etc/apache/include.d/$DUMMYAPACHECFG -a -x /etc/init.d/apache ]; then
  399. if [ -e /etc/apache/include.d/$DUMMYAPACHECFG-$user ]; then
  400. echo "/etc/apache/include.d/$DUMMYAPACHECFG-$user exists already. Ignoring..."
  401. else
  402. echo "# Created automatically by adduser.local
  403. <Location /$DUMMYAPACHESHAREDIR/$user>
  404. <Limit GET POST>
  405. require user $user
  406. </Limit>
  407. </Location>" \
  408. > /etc/apache/include.d/$DUMMYAPACHECFG-$user
  409. apache_reload_needed="1"
  410. fi
  411. fi
  412. fi
  413. fi
  414. echo "."
  415. done
  416. if [ $XCHANGE ]; then
  417. for USER in $(ls $XDIRREAL); do
  418. id $user >/dev/null 2>&1 || rm -rf $XDIRREAL/$user
  419. done
  420. fi
  421. if [ "$apache_reload_needed" ]; then
  422. apache_do_reload=""
  423. case runmode in
  424. interactive)
  425. echo -n "Apache config changed. Reload Apache now (Y/n)? "
  426. read apache_reload
  427. case $apache_reload in
  428. y|Y|"")
  429. apache_do_reload="1"
  430. ;;
  431. esac
  432. ;;
  433. force)
  434. apache_do_reload="1"
  435. ;;
  436. *)
  437. echo "Apache config has changed. Remember to reload Apache...!"
  438. ;;
  439. esac
  440. if "$apache_do_reload" ]; then
  441. /etc/init.d/apache force-reload
  442. fi
  443. fi