Google


   


You are here: CodeIdol.com > Other > Ruby Cookbook > System Administration > Normalizing Ownership And Permissions In User Directories

SAVE
Digg
Shown on del.icio.us del.icio.us
See Whos Talking About This on Technorati Technorati
I've Reddit reddit

Recipe 23.9. Normalizing Ownership and Permissions in User Directories

Problem

You want to make make sure your users' home directories don't contain world-writable directories, directories owned by other users, or other potential security problems.

Solution

Use the etc library to look up a user's home directory and UID from the username. Then use Find.find to walk the directory trees, and File methods to check and modify access to each file.

We are looking out for any case where one user's home directory can be modified by some other user. Whenever we find such a case, we fix it with a File.chmod or File.chown call. In this program, the actual calls are commented out, so that you don't accidentally change your permissions when you just want to test out the program.

	#!/usr/bin/ruby -w
	# normalize_homes.rb

	require 'etc'
	require 'find'
	require 'optparse'

	def normalize_home(pwd_entry, maximum_perms=0775, dry_run=true)
	  uid, home = pwd_entry.uid, pwd_entry.dir
	  username = pwd_entry.name

	  puts "Scanning #{username}'s home of #{home}."

	  Find.find(home) do |f|
	  next unless File.exists? f
	    stat = File.stat(f)
	    file_uid, file_gid, mode = stat.uid, stat.gid, stat.mode

The most obvious thing we want to check is whether the user owns every file in their home directory. With occasional exceptions (such as files owned by the web server), a user should own the files in his or her home directory:

	# Does the user own the file?
	if file_uid != uid
	  begin
	    current_owner = Etc.getpwuid(file_uid).name
	  rescue ArgumentError # No such user; just use UID
	    current_owner = "uid #{file_uid}"
	  end
	  puts " CHOWN #{f}"
	  puts " Current owner is #{current_owner}, should be #{username}"
	  # File.chown(uid, nil, f) unless dry_run
	end

A less obvious check involves the Unix group that owns the file. A user can let other people work on a file in their home directory by giving ownership to a user group. But you can only give ownership to a group if you're a member of that group. If a user's home directory contains a file owned by a group the user doesn't belong to, something fishy is probably going on.

	# Does the user belong to the group that owns the file?
	begin
	  group = Etc.getgrgid(file_gid)
	  group_name = group.name
	rescue ArgumentError # No such group
	  group_name = "gid #{file_gid}"
	end
	unless group && (group.mem.member?(username) || group.name == username)
	  puts " CHGRP #{f}"
	  puts " Current group is #{group_name}, and #{username} doesn't belong."
	  # File.chown(nil, uid, f) unless dry_run
	end

Finally, we'll check each file's permissions and make sure they are no more permissive than the value passed in as maximum_perms. The default value of 0775 allows any kind of file except a world-writable file. If normalize_home finds a world-writable file, it will flip the world-writable bit and leave the rest of the permissions alone:

	    # Does the file have more than the maximum allowed permissions?
	    perms = mode & 0777                # Drop non-permission bits
	    should_be = perms & maximum_perms
	    if perms != should_be
	      puts " CHMOD #{f}"
	      puts " Current perms are #{perms.to_s(8)}, " +
	           "should be #{should_be.to_s(8)}"
	      # File.chmod(perms & maximum_perms, f) unless dry_run
	    end
	  end
	end

All that's left to do is a simple command-line interface to the normalize_home method:

	dry_run = false
	opts = OptionParser.new do |opts|
	  opts.on("-D", "--dry-run",
	          "Display changes to be made, don't make them.") do
	    dry_run = true
	  end

	  opts.on_tail("-h", "--help", "display this help and exit") do
	    puts opts
	    exit
	  end
	end
	opts.banner = "Usage: #{__FILE__} [--dry-run] username [username2, …]"
	opts.parse!(ARGV)

	# Make sure all the users exist.
	pwd_entries = ARGV.collect { |username| Etc.getpwnam(username) }

	# Normalize all given home  
directories.
	pwd_entries.each { |p| normalize_home(p, 0775, dry_run ) }

Discussion

Running this script on my home directory shows over 2,500 problems. These are mostly files owned by root, files owned by UIDs that don't exist on my system (these come from tarballs), and world-writable files. Below I give a sample of the embarrassment:

	$ ruby -D normalize_homes.rb leonardr

	Scanning leonardr's home of /home/leonardr.
	 CHOWN /home/leonardr/writing/Ruby Cookbook/sys-proctable-0.7.3/proctable.so
	  Current owner is root, should be leonardr
	 CHGRP /home/leonardr/writing/Ruby Cookbook/sys-proctable-0.7.3/proctable.so
	  Current group is root, and leonardr doesn't belong.
	…
	 CHOWN /home/leonardr/writing/Ruby Cookbook/rubygems-0.8.4/lib/rubygems.rb
	  Current owner is uid 501, should be leonardr
	 CHGRP /home/leonardr/writing/Ruby Cookbook/rubygems-0.8.4/lib/rubygems.rb
	  Current group is gid 501, and leonardr doesn't belong.
	…
	 CHMOD /home/leonardr/SORT/gogol-home-2002/mail
	  Current perms are 722, should be 720
	…

Running the script as root (and with the File.chmod and File.chown calls uncommented) fixes all the problems.

You can run the script as yourself to check your own home directory, and it'll fix permission problems on files you own. But if a file is owned by someone else, you can't take it back just because it's in your home directorythat's part of the problem with having a file owned by someone else in your home directory.

As usual with system administration scripts, normalize.homes.rb is only a starting point. You'll probably need to adapt this program to your specific purposes. For instance, you may want to leave certain files alone, especially files owned by root (who can modify anyone's home directory anyway) or by system processes such as the web server (usually user apache, httpd, or nobody).

See Also


SAVE
Digg
Shown on del.icio.us del.icio.us
See Whos Talking About This on Technorati Technorati
I've Reddit reddit

You are here: CodeIdol.com > Other > Ruby Cookbook > System Administration > Normalizing Ownership And Permissions In User Directories


ADBRITE ads links
   
Related tags







Popular Categories
Unix books and guides

AJAX popular information
C# language guides
Windows books and cookbooks

.......








Business Key Top Sites

be number one
rate your site




    С 2009 года мы стали переводить структура сайта на различные языки. Сайт теперь будет содержать книги не только на английском языке, но также и на других европейских языках, в том числе и на Русском языке.

    Русский Polski Francais Deutsch
    support sitemap terms

© CodeIdol Labs, 2007 - 2009