How To Set Up And Integrate An Ubuntu 10.04 LTSPv5 Server Into A Windows 2008 Active Directory Domain - Page 2
DHCP Server Settings
These are the settings you'll need to make so that a thin client can boot from thinserver.
default-lease-time 21600; max-lease-time 21600; option subnet-mask 255.255.255.0; option broadcast-address 10.255.255.255; option routers 10.0.0.1; option domain-name-servers 10.0.0.10 option domain-name "domain.internal"; option root-path "/opt/ltsp/i386"; host thinclient1 { next-server 10.0.0.10; hardware ethernet 00:AA:BB:CC:DD:EE; fixed-address 10.0.0.100; filename "ltsp/i386/pxelinux.0"; option root-path "10.0.0.10:/opt/ltsp/i386"; } host thinclient2 { next-server 10.0.0.10; hardware ethernet 00:BB:CC:DD:EE:FF; fixed-address 10.0.0.101; filename "ltsp/i386/pxelinux.0"; option root-path "10.0.0.10:/opt/ltsp/i386"; }
Thin Client Setup
To make things easier for my thin client users I installed the XPGnome theme. You can download it from here. The only change that I made to the stock install was that I modified the Start menus. I then installed Adobe Reader 9 and Skype.
I did have a problem with the "Log Out" icon not showing up. To fix it I found an icon on Google that was 48x48 and then used Gimp to scale it down to 32x32, 24x24, 22x22, and 16x16. Rename the icon system-log-out.png and save it to /usr/share/icons/GnomeXP/{icon size}/actions.
The final result looks like this.
To make these settings the default for all users that login to thinserver, copy from your home folder (or the user's home folder that installed the XPGnome theme) the .config, .gconf, .icons, .local, and .themes folders to /etc/skel. Remember moving forward any changes that you make that you want to apply to everyone will need to be copied over also.
Mounting Windows Shares at Login
There are a couple of ways to do this in Linux but I finally decided on using Bash and Perl scripts in conjunction with Ubuntu's "Startup Applications" to handle the mounting of Windows shares. I will include all scripts in this tutorial so that you can modify them to fit your environment and improve them as you see fit.
Before we continue, make sure that the NETLOGON share from dc.domain.internal is mounted on thinserver.domain.internal. I created a generic domain account that has permissions to only list the contents of the AD. For the sake of this example that account name is "public" with the password of "password".
Create a folder to mount the share to.
sudo mkdir /mnt/logon
Mount the NETLOGON share by adding this entry into your /etc/fstab file.
//dc.domain.internal/netlogon /mnt/logon cifs username=public,password=password 0 0
Mount the share.
sudo mount -a
The scripts used depend on each user having their own login batch file in the NETLOGON share and their own share on server.domain.internal. Here is a batch file for user "John Doe" with username "jdoe". The batch file name is jdoe.bat. You can use just one batch file and hardcode the name into the script.
@echo off NET USE S: \\server\common NET USE T: \\server\IT
Create the win_share.sh script and save it to /usr/local/bin/. The win_share.sh script checks to see if the .mount.sh and .umount.sh scripts for the user logging in exist and if they do delete them. It then creates new .mount.sh and .umount.sh scripts by running the /usr/local/bin/mount.pl Perl script. Finally it mounts the users shares by running the .mount.sh script. The user shouldn't get prompted for a password since the script uses Kerberos to authenticate on server.domain.internal.
#!/bin/sh # Check to see if .mount.sh and .umount.sh exist, if so delete them! if [ -f /home/$USER/.mount.sh ]; then rm /home/$USER/.mount.sh fi if [ -f /home/$USER/.umount.sh ]; then rm /home/$USER/.umount.sh fi # Create the .mount.sh and .umount.sh scripts from users batch file /usr/local/bin/mount.pl $USER # Mount network shares when logging on. /home/$USER/.mount.sh
Create the mount.pl script in /usr/local/bin/.
#!/usr/bin/perl # Build dynamic ~user/.mount.sh based on logon.bat $user = $ARGV[0]; $file = "/mnt/logonbat/$user.bat"; # <-- Change this from $user to the name of the batch script if you only use one. die if ! $user; die if ! -e $file; open (PAM_CONF, ">/home/$user/.mount.sh"); open (LOGOFF, ">/home/$user/.umount.sh"); print PAM_CONF qq{#!/bin/sh if [ ! -d /home/$user/Home ]; then mkdir /home/$user/Home fi mount.cifs //server/$user /home/$user/Home -o username=$user,sec=krb5 }; print LOGOFF qq{#!/bin/sh if [ "`cat /proc/mounts | grep /home/$user/Home | wc -l`" -ge "1" ]; then umount.cifs /home/$user/Home fi \n}; my(@arr)=`cat /mnt/logonbat/$user.bat`; $mounts = parse_batfile(\@arr); foreach $mount (@$mounts) { chomp($mount); ($server,$share) = $mount =~ /\\\\(.*)\\(.*)/; $share =~ tr/\cM//d; $mnt = $share; # skip AUDIT. It's for PCs only next if $mnt =~ /AUDIT/; # skip personal shares. next if lc("$mnt") eq lc("$user"); next if ! $mnt; #strip dollar sign from mount point $mnt =~ s/\$$//; # make sure mount point is unique $mnt .= "-$server" if $seen{$mnt}++; # upshift first letter of mnt point $mnt =~ s/^(.)(.*)/\u$1$2/g; # print PAM_CONF "volume $user cifs $server $share /home/$user/$mnt - - -\n"; print PAM_CONF qq{if [ ! -d /home/$user/$mnt ]; then mkdir /home/$user/$mnt fi mount.cifs //$server/$mnt /home/$user/$mnt -o username=$user,sec=krb5 \n}; print LOGOFF qq{if [ "`cat /proc/mounts | grep /home/$user/$mnt | wc -l`" -ge "1" ]; then umount.cifs /home/$user/$mnt fi \n}; } close PAM_CONF; close LOGOFF; system ("chown $user:16777729 /home/$user/.mount.sh"); # 16777729 is my GID for "Domain Users" system ("chown $user:16777729 /home/$user/.umount.sh"); # 16777729 is my GID for "Domain Users" system ("chmod +x /home/$user/.mount.sh"); system ("chmod +x /home/$user/.umount.sh"); # All done sub parse_batfile { my($file) = @_; my(@mounts); foreach $line (@$file) { (@val) = split / /,$line; if (uc($val[0]) eq "NET" && uc($val[1]) eq "USE") { push (@mounts,$val[3]); } if ($val[0] eq "CALL") { my($match) = $val[1] =~ /\\\\.*\\NETLOGON\\(.*)/ ; if ($match) { chop($match); my(@arr)=`cat /mnt/logonbat/$match`; $mounts = parse_batfile(\@arr); unshift @mounts, @$mounts; } } } return \@mounts; }
This is what the .mount.sh script looks like for jdoe.
#!/bin/sh if [ ! -d /home/jdoe/Home ]; then mkdir /home/jdoe/Home fi mount.cifs //server/jdoe /home/jdoe/Home -o username=jdoe,sec=krb5 if [ ! -d /home/jdoe/common ]; then mkdir /home/jdoe/common fi mount.cifs //server/common /home/jdoe/common -o username=jdoe,sec=krb5 if [ ! -d /home/jdoe/IT ]; then mkdir /home/jdoe/IT fi mount.cifs //server/IT /home/jdoe/IT -o username=jdoe,sec=krb5
Once you have win_share.sh and mount.pl scripts in place, create the "Startup Application" to run it at login. To create the "Startup Application" go to "Preferences/Startup Applications".
Removing Windows Shares at Log off
To remove the Windows shares that were mounted at login I used pam_script.so. Pam_script is a PAM module that among other things will allow you to run scripts at session login and logoff. The reason why I didn't use pam_script for the login is because it runs as root and the win_share.sh and mount.pl scripts depend on the $USER variable. Download the libpam-script package from here.
Install libpam-script:
sudo dpkg -i libpam-script_1.1.4-1_i386.deb
This is the .umount.sh script that was created from the mount.pl Perl script for the user jdoe.
#!/bin/sh if [ "`cat /proc/mounts | grep /home/jdoe/Home | wc -l`" -ge "1" ]; then umount.cifs /home/jdoe/Home fi if [ "`cat /proc/mounts | grep /home/jdoe/common | wc -l`" -ge "1" ]; then umount.cifs /home/jdoe/common fi if [ "`cat /proc/mounts | grep /home/jdoe/IT | wc -l`" -ge "1" ]; then umount.cifs /home/jdoe/IT fi
Create and edit the /usr/share/libpam-script/pam_script_ses_close file.
#!/bin/sh # pam_script_ses_close script to remove windows shares /home/$PAM_USER/.umount.sh 2>&1 >> /var/log/umount.log
Add this line to /etc/pam.d/common-session:
session optional pam_script.so
Test to make sure that it's working as expected.
Passwordless SSH with Kerberos
One of the benefits of having a Kerberos enabled server is that you can now enable passwordless login via SSH. To make this work you need to have both your Linux workstation and server on the domain with Kerberos configured correctly.
Make these changes in the /etc/ssh/sshd_config file on thinserver:
# GSSAPI options GSSAPIAuthentication yes GSSAPICleanupCredentials yes UseDNS yes
Make these changes in the /etc/ssh/ssh_config file on your Linux workstation:
GSSAPIAuthentication yes GSSAPIDelegateCredentials yes
Test ssh to make sure that authentication is working with Kerberos. Try to login to thinserver from your workstation.
ssh -v thinserver
If authentication with Kerberos succeeded you shouldn't be promted for a password and you should see the "debug1: Authentication Succeeded (gssapi-with-mic) message:
debug1: Next authentication method: gssapi-keyex debug1: No valid Key exchange context debug1: Next authentication method: gssapi-with-mic debug1: Delegating credentials debug1: Delegating credentials debug1: Authentication succeeded (gssapi-with-mic).
Problems and Solutions
These are some of the other issues that I came accross. Hopefully they'll help someone.
PROBLEM : LTSP client authenticates but logs out immediately
SOLUTION: gconftool-2 --direct --config-source xml:readwrite:/etc/gconf/gconf.xml.mandatory --type string --set /desktop/gnome/session/required_components/windowmanager metacity
PROBLEM : No VNC on thin clients
SOLUTION: http://bootpolish.net/home_ltsp_installx11vnconltsp5
PROBLEM : Change the default login screen to a custom one
SOLUTION: https://help.ubuntu.com/community/EdubuntuFAQ
PROBLEM : How to setup root password on thin client
SOLUTION: https://help.ubuntu.com/community/EdubuntuFAQ
PROBLEM : No logout icon
SOLUTION: http://ubuntuforums.org/archive/index.php/t-815188.html