Complete Guide to Bash File Permissions and Ownership

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

  1. Three permission classes: User (owner), Group, Others
  2. Three permission types: Read (r=4), Write (w=2), Execute (x=1)
  3. Special permissions: Setuid (4), Setgid (2), Sticky bit (1)
  4. Default permissions: Controlled by umask
  5. ACLs: Fine-grained permissions beyond standard POSIX
  6. File attributes: Additional security features with chattr

Best Practices Summary

ScenarioRecommended Permissions
Regular files644 (rw-r--r--)
Executable scripts755 (rwxr-xr-x)
Private files600 (rw-------)
Private directories700 (rwx------)
Shared directories775 (rwxrwxr-x)
SSH private keys600 (rw-------)
Web directories755 (rwxr-xr-x)
Upload directories1777 (rwxrwxrwt)
Configuration files640 (rw-r-----)

Security Guidelines

  1. Principle of least privilege: Give minimum permissions needed
  2. Regular audits: Check for world-writable files and setuid binaries
  3. Secure defaults: Use appropriate umask (022 for system, 077 for personal)
  4. Protect sensitive files: SSH keys, config files should be 600/700
  5. Use groups: Manage team access through group permissions
  6. Avoid 777: Never use full permissions unless absolutely necessary
  7. Monitor changes: Track permission changes on critical files
  8. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper