Introduction to File Permissions
File permissions and ownership are fundamental concepts in Unix/Linux systems that control access to files and directories. Understanding these concepts is crucial for system security, multi-user environments, and proper file management.
Key Concepts
- Ownership: Every file has a user owner and group owner
- Permissions: Read (r), Write (w), Execute (x) for three classes
- Classes: User (owner), Group, Others (everyone else)
- Special Permissions: Setuid, Setgid, Sticky bit
- UMASK: Default permission mask for new files
1. Viewing Permissions and Ownership
Using ls -l
# View file permissions ls -l file.txt # -rw-r--r-- 1 user group 1024 Jan 1 10:00 file.txt # View directory permissions ls -ld directory/ # drwxr-xr-x 2 user group 4096 Jan 1 10:00 directory/ # View all files including hidden ls -la # View with human-readable sizes ls -lh # Recursive listing ls -lR # Explanation of output: # -rw-r--r-- # ││││││││└─ Others permissions (r--) # ││││││└── Group permissions (r--) # │││││└─── User permissions (rw-) # ││││└──── Number of hard links # │││└───── Special permissions (if any) # ││└────── Group owner # │└─────── User owner # └──────── File type (- = file, d = directory, l = symlink)
Using stat
# Detailed file information stat file.txt # Output: # File: file.txt # Size: 1024 Blocks: 8 IO Block: 4096 regular file # Device: 801h/2049d Inode: 1234567 Links: 1 # Access: (0644/-rw-r--r--) Uid: ( 1000/ user) Gid: ( 1000/ group) # Access: 2024-01-01 10:00:00.000000000 # Modify: 2024-01-01 10:00:00.000000000 # Change: 2024-01-01 10:00:00.000000000 # Custom stat output stat -c "%a %A %n" * # Permissions in octal, symbolic, and name # Get specific information stat -c "%U" file.txt # Get owner stat -c "%G" file.txt # Get group stat -c "%a" file.txt # Get permissions in octal stat -c "%A" file.txt # Get permissions in symbolic
Understanding Permission Notation
# Symbolic notation (rwx) # r = read (4) # w = write (2) # x = execute (1) # - = no permission # Examples: # rw------- (600) - Owner can read/write, nothing for others # rw-r--r-- (644) - Owner read/write, others read only # rwxr-xr-x (755) - Owner all, others read/execute # rwx------ (700) - Only owner has all permissions # Octal notation # 0 = --- (no permissions) # 1 = --x (execute only) # 2 = -w- (write only) # 3 = -wx (write and execute) # 4 = r-- (read only) # 5 = r-x (read and execute) # 6 = rw- (read and write) # 7 = rwx (read, write, execute) # Examples: chmod 755 script.sh # rwxr-xr-x chmod 644 file.txt # rw-r--r-- chmod 700 private/ # rwx------
2. Changing Permissions (chmod)
Symbolic Mode
# Basic symbolic syntax # u = user (owner) # g = group # o = others # a = all (ugo) # + = add permission # - = remove permission # = = set exactly # Add execute permission for user chmod u+x script.sh # Remove write permission for others chmod o-w file.txt # Add read and execute for group chmod g+rx directory/ # Set exactly rwx for user, rx for group, nothing for others chmod u=rwx,g=rx,o= file.txt # Add execute for all chmod a+x script.sh # Remove write from all chmod a-w file.txt # Multiple changes chmod u+x,g-w,o=r file.txt # Recursive changes chmod -R u+x directory/ # Examples chmod u+x,g+x script.sh # Add execute for user and group chmod go-w file.txt # Remove write from group and others chmod a=rw file.txt # Set read/write for everyone
Numeric (Octal) Mode
# Three-digit octal (owner, group, others) chmod 755 script.sh # rwxr-xr-x chmod 644 file.txt # rw-r--r-- chmod 700 private/ # rwx------ chmod 777 public/ # rwxrwxrwx (dangerous!) chmod 600 secret.txt # rw------- # Four-digit octal (includes special permissions) chmod 4755 script.sh # rwsr-xr-x (setuid) chmod 2755 directory/ # rwxr-sr-x (setgid) chmod 1777 /tmp # rwxrwxrwt (sticky bit) # Common permission sets chmod 755 script.sh # Executable scripts chmod 644 *.txt # Regular text files chmod 600 .ssh/id_rsa # Private SSH key chmod 700 .ssh # SSH directory chmod 755 public_html # Web directory chmod 640 config.cfg # Configuration readable by group # Calculate permissions # To get 754: 7 (rwx) for owner, 5 (r-x) for group, 4 (r--) for others chmod 754 file.txt
Common Permission Scenarios
#!/bin/bash
# Make script executable
make_executable() {
local file="$1"
if [ -f "$file" ]; then
chmod +x "$file"
echo "✓ Made executable: $file"
fi
}
# Secure private key
secure_ssh_key() {
local key="$HOME/.ssh/id_rsa"
if [ -f "$key" ]; then
chmod 600 "$key"
chmod 700 "$HOME/.ssh"
echo "✓ SSH key secured"
fi
}
# Set up shared directory
setup_shared() {
local dir="$1"
local group="$2"
mkdir -p "$dir"
chgrp -R "$group" "$dir"
chmod -R 775 "$dir"
chmod g+s "$dir" # Setgid for inheritance
echo "✓ Shared directory setup: $dir"
}
# Reset permissions to safe defaults
safe_permissions() {
local dir="$1"
# Directories: 755
find "$dir" -type d -exec chmod 755 {} \;
# Files: 644
find "$dir" -type f -exec chmod 644 {} \;
# Executable scripts: 755
find "$dir" -name "*.sh" -type f -exec chmod 755 {} \;
echo "✓ Safe permissions applied to $dir"
}
3. Changing Ownership (chown, chgrp)
chown - Change Owner
# Change owner only sudo chown user file.txt # Change owner and group sudo chown user:group file.txt # Change group only (with colon) sudo chown :group file.txt # Change owner and group (using dot) sudo chown user.group file.txt # Legacy syntax # Recursive change sudo chown -R user:group directory/ # Change only if current owner matches sudo chown --from=current_user user file.txt # Change only if current group matches sudo chown --from=:current_group :group file.txt # Reference another file's ownership sudo chown --reference=ref_file target_file # Verbose output sudo chown -v user:group file.txt # Examples sudo chown www-data:www-data /var/www/html/ -R sudo chown user:users /home/user/documents/ -R sudo chown :developers project/ -R
chgrp - Change Group Only
# Change group sudo chgrp group file.txt # Recursive change sudo chgrp -R group directory/ # Verbose output sudo chgrp -v group file.txt # Reference file sudo chgrp --reference=ref_file target_file # Preserve root directory sudo chgrp -hR group symbolic_link/ # Don't follow symlinks # Examples sudo chgrp developers project/ sudo chgrp -R www-data /var/www/html/ sudo chgrp users /home/shared/ -R
Advanced Ownership Management
#!/bin/bash
# Reset ownership to user's primary group
fix_ownership() {
local dir="$1"
local user="$2"
# Get user's primary group
group=$(id -gn "$user")
sudo chown -R "$user:$group" "$dir"
echo "✓ Ownership fixed for $dir"
}
# Set up shared project
setup_project() {
local project="$1"
local group="$2"
local users=("${@:3}")
# Create project directory
sudo mkdir -p "/projects/$project"
# Set group ownership
sudo chgrp -R "$group" "/projects/$project"
# Set setgid bit for inheritance
sudo chmod g+s "/projects/$project"
# Set permissions
sudo chmod 2775 "/projects/$project"
# Add users to group
for user in "${users[@]}"; do
sudo usermod -a -G "$group" "$user"
done
echo "✓ Project $project created for group $group"
}
# Transfer files to another user
transfer_files() {
local src="$1"
local from_user="$2"
local to_user="$3"
# Change ownership
sudo chown -R "$to_user" "$src"
# Update home directory permissions if needed
if [[ "$src" == "/home/$from_user"* ]]; then
sudo chmod 700 "/home/$to_user"
fi
echo "✓ Files transferred from $from_user to $to_user"
}
# Audit ownership
audit_ownership() {
local dir="$1"
echo "Ownership audit for $dir"
echo "========================"
find "$dir" -printf "%u:%g %p\n" 2>/dev/null | sort | uniq -c | while read count owner path; do
echo "$count files owned by $owner"
done
}
4. Special Permissions
Setuid (Set User ID) - 4xxx
# Setuid bit (user gets owner's permissions when executing) chmod u+s program chmod 4755 program # rwsr-xr-x # Remove setuid chmod u-s program chmod 755 program # rwxr-xr-x # Example: /usr/bin/passwd has setuid ls -l /usr/bin/passwd # -rwsr-xr-x 1 root root Jan 1 10:00 /usr/bin/passwd # Find setuid files find / -perm -4000 -type f 2>/dev/null # Check for setuid if [ -u "$file" ]; then echo "$file has setuid bit" fi
Setgid (Set Group ID) - 2xxx
# Setgid on files (executes with group privileges) chmod g+s program chmod 2755 program # rwxr-sr-x # Setgid on directories (new files inherit group) chmod g+s directory/ chmod 2775 directory/ # drwxrwsr-x # Remove setgid chmod g-s directory/ # Find setgid files find / -perm -2000 -type f 2>/dev/null # Find setgid directories find / -perm -2000 -type d 2>/dev/null # Example: Shared directory setup mkdir shared chgrp developers shared chmod 2775 shared touch shared/file.txt # Inherits 'developers' group
Sticky Bit - 1xxx
# Sticky bit on directories (only owner can delete files)
chmod +t directory/
chmod 1777 /tmp # drwxrwxrwt
# Remove sticky bit
chmod -t directory/
# Find directories with sticky bit
find / -perm -1000 -type d 2>/dev/null
# Example: /tmp has sticky bit
ls -ld /tmp
# drwxrwxrwt 1 root root Jan 1 10:00 /tmp
# Check for sticky bit
if [ -k "$dir" ]; then
echo "$dir has sticky bit"
fi
# Safe shared directory with sticky bit
setup_shared_with_sticky() {
local dir="$1"
local group="$2"
mkdir -p "$dir"
chgrp "$group" "$dir"
chmod 1777 "$dir" # All can write, only owner can delete
echo "✓ Shared directory with sticky bit: $dir"
}
Combined Special Permissions
# All special permissions
chmod 7777 file # rwsrwsrwt (very dangerous!)
# Common combinations
chmod 4755 file # rwsr-xr-x (setuid)
chmod 2755 file # rwxr-sr-x (setgid)
chmod 1777 dir # rwxrwxrwt (sticky)
chmod 6777 file # rwsrwsrwx (all special + full permissions)
# Safe shared directory with inheritance
chmod 2770 shared/ # rwxrws--- (group inheritance, no others)
# Check special permissions
check_special_perms() {
local file="$1"
perms=$(stat -c "%a" "$file")
if [ ${#perms} -eq 4 ]; then
case "${perms:0:1}" in
4) echo "Setuid set" ;;
2) echo "Setgid set" ;;
1) echo "Sticky bit set" ;;
6) echo "Setuid and setgid set" ;;
5) echo "Setuid and sticky set" ;;
3) echo "Setgid and sticky set" ;;
7) echo "All special permissions set" ;;
esac
fi
}
5. Default Permissions (umask)
Understanding umask
# View current umask umask # Output: 0022 # View in symbolic form umask -S # Output: u=rwx,g=rx,o=rx # How umask works: # Default file permissions: 666 (rw-rw-rw-) # Default directory permissions: 777 (rwxrwxrwx) # umask subtracts permissions # umask 022: # Files: 666 - 022 = 644 (rw-r--r--) # Directories: 777 - 022 = 755 (rwxr-xr-x) # umask 002: # Files: 666 - 002 = 664 (rw-rw-r--) # Directories: 777 - 002 = 775 (rwxrwxr-x) # umask 077: # Files: 666 - 077 = 600 (rw-------) # Directories: 777 - 077 = 700 (rwx------)
Setting umask
# Set numeric umask
umask 022
umask 002
umask 077
# Set symbolic umask
umask u=rwx,g=rx,o=rx # Same as 022
umask u=rwx,g=rwx,o=r # Same as 002
umask u=rwx,g=,o= # Same as 077
# Set in shell configuration (~/.bashrc)
echo "umask 022" >> ~/.bashrc
# Set system-wide (/etc/profile)
echo "umask 022" >> /etc/profile
# Different umask for different users
setup_umask() {
case $(whoami) in
root) umask 022 ;;
developer) umask 002 ;;
guest) umask 077 ;;
esac
}
Practical umask Examples
#!/bin/bash
# Secure environment
secure_umask() {
umask 077 # Only owner can access new files
echo "✓ Secure umask set: $(umask)"
}
# Collaborative environment
collab_umask() {
umask 002 # Group can write new files
echo "✓ Collaborative umask set: $(umask)"
}
# Calculate effective permissions
calculate_perms() {
local base="${1:-666}" # Default for files
local umask_val="${2:-$(umask)}"
# Remove leading zeros if present
umask_val=$(echo "$umask_val" | sed 's/^0*//')
# Calculate
result=$((base - umask_val))
echo "Base: $base, Umask: $umask_val, Result: $result"
# Show symbolic
echo "Permissions: $(stat -c "%A" <(exit) 2>/dev/null | sed "s/........./$result/")"
}
# Test different umasks
test_umask() {
local test_file="/tmp/umask_test.$$"
for mask in 000 022 002 077 027; do
umask $mask
touch "$test_file"
perms=$(ls -l "$test_file" | cut -d' ' -f1)
echo "umask $mask: $perms"
rm "$test_file"
done
}
6. Advanced Permission Management
Access Control Lists (ACL)
# Install ACL tools (if not present)
sudo apt install acl # Debian/Ubuntu
sudo yum install acl # RHEL/CentOS
# View ACL
getfacl file.txt
# Set ACL
setfacl -m u:user:rwx file.txt # Add for specific user
setfacl -m g:group:rx file.txt # Add for specific group
setfacl -m o::r file.txt # Set for others
setfacl -m m::rwx file.txt # Set mask
# Remove ACL
setfacl -x u:user file.txt # Remove specific user
setfacl -b file.txt # Remove all ACLs
# Recursive ACL
setfacl -R -m u:user:rwx directory/
setfacl -R -m g:group:rx directory/
# Default ACL (inherited)
setfacl -d -m u:user:rwx directory/
# Examples
# Give user john read/write access to project
setfacl -m u:john:rw project/
# Give web server read access to logs
setfacl -m g:www-data:r /var/log/app/
# Set up shared directory with ACL
setup_acl_share() {
local dir="$1"
shift
local users=("$@")
mkdir -p "$dir"
# Set base permissions
setfacl -b "$dir"
setfacl -m g::rwx "$dir"
setfacl -m o::--- "$dir"
# Add users
for user in "${users[@]}"; do
setfacl -m "u:$user:rwx" "$dir"
done
# Set defaults for new files
setfacl -d -m g::rwx "$dir"
for user in "${users[@]}"; do
setfacl -d -m "u:$user:rwx" "$dir"
done
echo "✓ ACL shared directory: $dir"
}
File Attributes (chattr)
# View attributes
lsattr file.txt
# Set attributes
sudo chattr +i file.txt # Immutable - cannot modify/delete
sudo chattr +a file.txt # Append only
sudo chattr +c file.txt # Compressed
sudo chattr +s file.txt # Secure deletion
sudo chattr +u file.txt # Undeletable
# Remove attributes
sudo chattr -i file.txt
# Common attributes
# i - immutable (even root can't modify)
# a - append only (for logs)
# d - no dump (exclude from backup)
# c - compressed
# s - secure deletion
# u - undeletable
# Examples
# Protect critical configuration
sudo chattr +i /etc/passwd /etc/shadow
# Log file that can only be appended
sudo chattr +a /var/log/app.log
# Find immutable files
find / -type f -exec lsattr {} \; 2>/dev/null | grep "^....i"
# Check if file is immutable
if lsattr "$file" 2>/dev/null | grep -q "^....i"; then
echo "$file is immutable"
fi
7. Permission Management Scripts
Permission Audit Script
#!/bin/bash
# Comprehensive permission audit
audit_permissions() {
local dir="${1:-.}"
local report="/tmp/audit_$(date +%Y%m%d).txt"
{
echo "Permission Audit Report - $(date)"
echo "==================================="
echo
echo "Audit directory: $dir"
echo
# World-writable files
echo "World-writable files:"
find "$dir" -type f -perm -002 -ls 2>/dev/null | while read line; do
echo " $line"
done
echo
# World-writable directories
echo "World-writable directories:"
find "$dir" -type d -perm -002 -ls 2>/dev/null | while read line; do
echo " $line"
done
echo
# Files with setuid
echo "Setuid files:"
find "$dir" -type f -perm -4000 -ls 2>/dev/null | while read line; do
echo " $line"
done
echo
# Files with setgid
echo "Setgid files:"
find "$dir" -type f -perm -2000 -ls 2>/dev/null | while read line; do
echo " $line"
done
echo
# Directories with sticky bit
echo "Directories with sticky bit:"
find "$dir" -type d -perm -1000 -ls 2>/dev/null | while read line; do
echo " $line"
done
echo
# Files without owner in passwd
echo "Files with no owner:"
find "$dir" -nouser -ls 2>/dev/null | while read line; do
echo " $line"
done
echo
# Files without group in group
echo "Files with no group:"
find "$dir" -nogroup -ls 2>/dev/null | while read line; do
echo " $line"
done
} > "$report"
echo "Audit report saved to: $report"
cat "$report"
}
# Fix common permission issues
fix_permissions() {
local dir="$1"
# Fix directory permissions
find "$dir" -type d -exec chmod 755 {} \;
# Fix file permissions
find "$dir" -type f -exec chmod 644 {} \;
# Fix executable scripts
find "$dir" -name "*.sh" -type f -exec chmod 755 {} \;
# Remove world-writable bits
find "$dir" -type f -perm -002 -exec chmod o-w {} \;
find "$dir" -type d -perm -002 -exec chmod o-w {} \;
echo "✓ Permissions fixed in $dir"
}
Permission Comparison Script
#!/bin/bash
# Compare permissions between two files/directories
compare_permissions() {
local path1="$1"
local path2="$2"
echo "Comparing:"
echo " $path1"
echo " $path2"
echo
# Get permissions
perm1=$(stat -c "%a %A" "$path1" 2>/dev/null)
perm2=$(stat -c "%a %A" "$path2" 2>/dev/null)
if [ $? -ne 0 ]; then
echo "Error: Cannot stat one of the paths"
return 1
fi
echo "Permissions:"
echo " $path1: $perm1"
echo " $path2: $perm2"
if [ "$perm1" = "$perm2" ]; then
echo "✓ Permissions match"
else
echo "✗ Permissions differ"
fi
echo
# Compare ownership
owner1=$(stat -c "%U:%G" "$path1")
owner2=$(stat -c "%U:%G" "$path2")
echo "Ownership:"
echo " $path1: $owner1"
echo " $path2: $owner2"
if [ "$owner1" = "$owner2" ]; then
echo "✓ Ownership matches"
else
echo "✗ Ownership differs"
fi
}
# Synchronize permissions from reference
sync_permissions() {
local reference="$1"
local target="$2"
# Get reference permissions and ownership
perms=$(stat -c "%a" "$reference")
owner=$(stat -c "%U" "$reference")
group=$(stat -c "%G" "$reference")
# Apply to target
if [ -d "$target" ]; then
find "$target" -type d -exec chmod "$perms" {} \;
find "$target" -type f -exec chmod "$(stat -c "%a" "$reference")" {} \;
else
chmod "$perms" "$target"
fi
chown -R "$owner:$group" "$target"
echo "✓ Permissions synced from $reference to $target"
}
Permission Backup and Restore
#!/bin/bash
# Backup permissions
backup_permissions() {
local dir="$1"
local backup_file="${2:-perms_backup.txt}"
find "$dir" -printf "%p %m %u %g\n" 2>/dev/null > "$backup_file"
echo "Permissions backed up to: $backup_file"
}
# Restore permissions from backup
restore_permissions() {
local backup_file="$1"
local dir="${2:-.}"
if [ ! -f "$backup_file" ]; then
echo "Error: Backup file not found"
return 1
fi
while read path perms user group; do
# Check if file exists
if [ -e "$path" ]; then
chmod "$perms" "$path" 2>/dev/null
chown "$user:$group" "$path" 2>/dev/null
echo "Restored: $path"
fi
done < "$backup_file"
echo "✓ Permissions restored"
}
# Create permission snapshot
snapshot_permissions() {
local dir="$1"
local snapshot="/tmp/perms_snapshot_$(date +%Y%m%d_%H%M%S).txt"
{
echo "Permission Snapshot - $(date)"
echo "Directory: $dir"
echo "================================="
echo
find "$dir" -exec stat -c "%n %a %u %g" {} \; 2>/dev/null | sort
} > "$snapshot"
echo "Snapshot saved: $snapshot"
}
8. Permission Testing and Validation
Test Permission Functions
#!/bin/bash
# Test if user has specific permissions
test_permissions() {
local file="$1"
echo "Testing permissions for: $file"
echo "=============================="
# Read test
if [ -r "$file" ]; then
echo "✓ Read permission"
else
echo "✗ No read permission"
fi
# Write test
if [ -w "$file" ]; then
echo "✓ Write permission"
else
echo "✗ No write permission"
fi
# Execute test
if [ -x "$file" ]; then
echo "✓ Execute permission"
else
echo "✗ No execute permission"
fi
# Special bits
if [ -u "$file" ]; then
echo "✓ Setuid set"
fi
if [ -g "$file" ]; then
echo "✓ Setgid set"
fi
if [ -k "$file" ]; then
echo "✓ Sticky bit set"
fi
}
# Validate permission requirements
validate_permissions() {
local file="$1"
local required_perms="$2"
current=$(stat -c "%a" "$file" 2>/dev/null)
if [ "$current" = "$required_perms" ]; then
echo "✓ Permissions OK: $file ($current)"
return 0
else
echo "✗ Permission mismatch: $file (have $current, need $required_perms)"
return 1
fi
}
# Check secure permissions
check_secure() {
local file="$1"
local issues=0
# World-writable check
if [ "$(stat -c "%a" "$file" | cut -c3)" -eq 7 ] || \
[ "$(stat -c "%a" "$file" | cut -c3)" -eq 6 ]; then
echo "⚠ World-writable: $file"
issues=$((issues + 1))
fi
# Group-writable check for sensitive files
if [[ "$file" == *"ssh"* ]] || [[ "$file" == *"config"* ]]; then
if [ "$(stat -c "%a" "$file" | cut -c2)" -eq 7 ] || \
[ "$(stat -c "%a" "$file" | cut -c2)" -eq 6 ]; then
echo "⚠ Group-writable sensitive file: $file"
issues=$((issues + 1))
fi
fi
# Owner check
if [ "$(stat -c "%U" "$file")" != "$USER" ] && [ "$(stat -c "%U" "$file")" != "root" ]; then
echo "⚠ Wrong owner: $file"
issues=$((issues + 1))
fi
return $issues
}
9. Permission Best Practices
Security Guidelines
#!/bin/bash
# Secure file creation
secure_create() {
local file="$1"
# Set restrictive umask
local old_umask=$(umask)
umask 077
# Create file
touch "$file"
# Restore umask
umask "$old_umask"
echo "✓ Securely created: $file"
}
# Secure directory for web application
secure_web_dir() {
local dir="$1"
# Create directories
mkdir -p "$dir"/{public,private,logs,tmp}
# Public web root
chmod 755 "$dir/public"
# Private files (config, includes)
chmod 700 "$dir/private"
# Logs - writable by web server
chmod 770 "$dir/logs"
chgrp www-data "$dir/logs"
# Temp - writable by all, sticky bit
chmod 1777 "$dir/tmp"
echo "✓ Secure web directory created: $dir"
}
# Production deployment permissions
deploy_permissions() {
local app_dir="$1"
local web_user="${2:-www-data}"
# Set ownership
chown -R "deploy:$web_user" "$app_dir"
# Base permissions
find "$app_dir" -type d -exec chmod 755 {} \;
find "$app_dir" -type f -exec chmod 644 {} \;
# Make executables
find "$app_dir" -name "*.sh" -exec chmod 755 {} \;
# Writable directories
for dir in cache logs uploads tmp; do
if [ -d "$app_dir/$dir" ]; then
chmod 775 "$app_dir/$dir"
chgrp "$web_user" "$app_dir/$dir"
fi
done
echo "✓ Deployment permissions set"
}
Permission Templates
#!/bin/bash
# Common permission templates
declare -A PERM_TEMPLATES=(
["private"]="700"
["private_group"]="750"
["shared"]="775"
["public"]="755"
["public_readonly"]="755"
["public_write"]="777"
["config"]="640"
["config_private"]="600"
["script"]="755"
["document"]="644"
["upload_dir"]="1777"
)
apply_template() {
local template="$1"
local target="$2"
if [ -z "${PERM_TEMPLATES[$template]}" ]; then
echo "Unknown template: $template"
return 1
fi
perms="${PERM_TEMPLATES[$template]}"
if [ -d "$target" ]; then
chmod -R "$perms" "$target"
else
chmod "$perms" "$target"
fi
echo "✓ Applied template '$template' ($perms) to $target"
}
# Usage
# apply_template "private" ~/.ssh
# apply_template "shared" /projects/shared
# apply_template "upload_dir" /tmp/uploads
10. Permission Troubleshooting
Common Permission Issues
#!/bin/bash
# Diagnose permission issues
diagnose_permission() {
local path="$1"
local user="${2:-$USER}"
echo "Diagnosing permissions for: $path"
echo "User: $user"
echo "================================="
# Check if path exists
if [ ! -e "$path" ]; then
echo "✗ Path does not exist"
return 1
fi
# Show current permissions
ls -ld "$path"
# Check ownership
owner=$(stat -c "%U" "$path")
group=$(stat -c "%G" "$path")
echo "Owner: $owner"
echo "Group: $group"
# Check user's group membership
groups=$(id -Gn "$user")
echo "User's groups: $groups"
# Determine access
if [ "$user" = "$owner" ]; then
echo "✓ User owns the file"
elif echo "$groups" | grep -q "$group"; then
echo "✓ User is in the file's group"
else
echo "User is 'other' for this file"
fi
# Check specific permissions
echo -n "Read access: "
if [ -r "$path" ]; then echo "✓"; else echo "✗"; fi
echo -n "Write access: "
if [ -w "$path" ]; then echo "✓"; else echo "✗"; fi
echo -n "Execute access: "
if [ -x "$path" ]; then echo "✓"; else echo "✗"; fi
}
# Fix common permission problems
fix_common_issues() {
local dir="$1"
# Fix home directory
if [[ "$dir" == "/home/"* ]]; then
chmod 755 "$dir"
echo "✓ Fixed home directory permissions"
fi
# Fix SSH directory
if [ -d "$dir/.ssh" ]; then
chmod 700 "$dir/.ssh"
chmod 600 "$dir/.ssh/id_rsa" 2>/dev/null
chmod 644 "$dir/.ssh/id_rsa.pub" 2>/dev/null
chmod 600 "$dir/.ssh/authorized_keys" 2>/dev/null
echo "✓ Fixed SSH permissions"
fi
# Fix web directories
if [[ "$dir" == *"public_html" ]] || [[ "$dir" == *"www"* ]]; then
find "$dir" -type d -exec chmod 755 {} \;
find "$dir" -type f -exec chmod 644 {} \;
echo "✓ Fixed web directory permissions"
fi
}
Permission Recovery
#!/bin/bash
# Emergency permission recovery
emergency_recovery() {
local dir="$1"
local log="/tmp/permission_recovery_$(date +%s).log"
{
echo "Emergency Permission Recovery - $(date)"
echo "========================================"
echo "Directory: $dir"
echo
# Backup current permissions
echo "Backing up current permissions..."
find "$dir" -printf "%p %m %u %g\n" > "${log}.backup"
# Reset to safe defaults
echo "Resetting to safe defaults..."
# Directories: 755
find "$dir" -type d -exec chmod 755 {} \; -print
# Files: 644
find "$dir" -type f -exec chmod 644 {} \; -print
# Executable scripts: 755
find "$dir" -name "*.sh" -type f -exec chmod 755 {} \; -print
echo
echo "Recovery complete. Backup saved to: ${log}.backup"
} 2>&1 | tee "$log"
echo "Recovery log saved to: $log"
}
# Restore from backup
restore_from_backup() {
local backup="$1"
if [ ! -f "$backup" ]; then
echo "Error: Backup file not found"
return 1
fi
while read -r path perms owner group; do
if [ -e "$path" ]; then
chmod "$perms" "$path" 2>/dev/null
chown "$owner:$group" "$path" 2>/dev/null
echo "Restored: $path"
fi
done < "$backup"
echo "✓ Restore complete"
}
11. Permission Monitoring
Monitor Permission Changes
#!/bin/bash
# Watch for permission changes
watch_permissions() {
local watch_dir="$1"
inotifywait -m -r --format '%w%f %e' "$watch_dir" 2>/dev/null | while read path event; do
if [[ "$event" == *"ATTRIB"* ]]; then
perms=$(stat -c "%a" "$path" 2>/dev/null)
owner=$(stat -c "%U:%G" "$path" 2>/dev/null)
echo "$(date '+%Y-%m-%d %H:%M:%S') - Permission change: $path ($perms) $owner"
fi
done
}
# Log permission changes to syslog
log_permission_changes() {
local dir="$1"
# Create baseline
find "$dir" -printf "%p %m %u %g\n" > "/tmp/perms_baseline.txt"
# Monitor for changes
while true; do
find "$dir" -printf "%p %m %u %g\n" > "/tmp/perms_current.txt"
diff "/tmp/perms_baseline.txt" "/tmp/perms_current.txt" | while read line; do
if [[ "$line" == ">"* ]]; then
logger -t perm_monitor "Permission changed: ${line:2}"
fi
done
mv "/tmp/perms_current.txt" "/tmp/perms_baseline.txt"
sleep 60
done
}
12. Permission Command Reference
Quick Reference
# View permissions ls -l file stat file getfacl file # Change permissions (symbolic) chmod u+x file # Add execute for user chmod g-w file # Remove write from group chmod o=r file # Set others to read-only chmod a+x file # Add execute for all # Change permissions (numeric) chmod 755 file # rwxr-xr-x chmod 644 file # rw-r--r-- chmod 700 file # rwx------ chmod 600 file # rw------- # Change ownership chown user file # Change owner chown user:group file # Change both chgrp group file # Change group only chown -R user:group directory/ # Recursive # Special permissions chmod u+s file # Setuid chmod g+s file # Setgid chmod +t dir # Sticky bit # Default permissions umask # View current umask umask 022 # Set umask umask -S # View symbolic umask # ACLs getfacl file setfacl -m u:user:rwx file setfacl -b file # File attributes lsattr file chattr +i file
Permission Tables
# Numeric to Symbolic Conversion Table # 0 = --- # 1 = --x # 2 = -w- # 3 = -wx # 4 = r-- # 5 = r-x # 6 = rw- # 7 = rwx # Common Permission Combinations # 400 = r-------- # 600 = rw------- # 644 = rw-r--r-- # 654 = rw-r-xr-- # 664 = rw-rw-r-- # 700 = rwx------ # 744 = rwxr--r-- # 750 = rwxr-x--- # 755 = rwxr-xr-x # 777 = rwxrwxrwx # Directory Permissions # 755 = drwxr-xr-x (typical) # 750 = drwxr-x--- (group access) # 700 = drwx------ (private) # 2775 = drwxrwsr-x (with setgid) # 1777 = drwxrwxrwt (with sticky)
Conclusion
File permissions and ownership are fundamental to Unix/Linux security:
Key Takeaways
- Three permission classes: User (owner), Group, Others
- Three permission types: Read (r=4), Write (w=2), Execute (x=1)
- Special permissions: Setuid (4), Setgid (2), Sticky bit (1)
- Default permissions: Controlled by umask
- ACLs: Fine-grained permissions beyond standard POSIX
- File attributes: Additional security features with chattr
Best Practices Summary
| Scenario | Recommended Permissions |
|---|---|
| Regular files | 644 (rw-r--r--) |
| Executable scripts | 755 (rwxr-xr-x) |
| Private files | 600 (rw-------) |
| Private directories | 700 (rwx------) |
| Shared directories | 775 (rwxrwxr-x) |
| SSH private keys | 600 (rw-------) |
| Web directories | 755 (rwxr-xr-x) |
| Upload directories | 1777 (rwxrwxrwt) |
| Configuration files | 640 (rw-r-----) |
Security Guidelines
- Principle of least privilege: Give minimum permissions needed
- Regular audits: Check for world-writable files and setuid binaries
- Secure defaults: Use appropriate umask (022 for system, 077 for personal)
- Protect sensitive files: SSH keys, config files should be 600/700
- Use groups: Manage team access through group permissions
- Avoid 777: Never use full permissions unless absolutely necessary
- Monitor changes: Track permission changes on critical files
- Backup permissions: Save permission metadata with backups
Understanding and properly managing file permissions is essential for system security and multi-user environments. The concepts may seem complex at first, but they become intuitive with practice.