secubox-openwrt/package/secubox/secubox-app-mailserver/files/usr/lib/mailserver/users.sh
CyberMind-FR a8eb8b1271 feat(p2p-intel): ZKP trust integration and IOC blockchain recording
P2P Mesh Intelligence implementation:
- Add ZKP trust bonus (+20) for verified peers in IOC validation
- Create blockchain.sh for permanent threat_ioc and ioc_feedback blocks
- Create feedback.sh for IOC effectiveness tracking and reputation updates
- Enhance gossip.sh IOC handler with ZKP-validated trust checks
- Add SCORE_IOC_EFFECTIVE (+5) and SCORE_IOC_FALSE_POSITIVE (-8) to reputation
- Add zkp_trust_bonus and feedback config options

fix(mailserver): Correct vmail UID from 102 to 5000

Dovecot was using wrong UID (102/redis instead of 5000/vmail) causing
permission denied errors when accessing mailboxes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-24 17:20:33 +01:00

217 lines
6.5 KiB
Bash

#!/bin/sh
# Mail Server User Management
CONFIG="mailserver"
get_container() {
uci -q get $CONFIG.main.container || echo "mailserver"
}
get_data_path() {
uci -q get $CONFIG.main.data_path || echo "/srv/mailserver"
}
# Add mail user
user_add() {
local email="$1"
local password="$2"
[ -z "$email" ] && { echo "Usage: user_add <email@domain>"; return 1; }
local user=$(echo "$email" | cut -d@ -f1)
local domain=$(echo "$email" | cut -d@ -f2)
local container=$(get_container)
local data_path=$(get_data_path)
# Validate
echo "$email" | grep -qE '^[^@]+@[^@]+\.[^@]+$' || { echo "Invalid email format"; return 1; }
# Create mailbox directory with Maildir structure
# Dovecot expects ~/Maildir/ so we create $domain/$user/Maildir/
local maildir="$data_path/mail/$domain/$user/Maildir"
mkdir -p "$maildir"/{cur,new,tmp}
chown -R 1000:1000 "$data_path/mail/$domain/$user"
# Add to virtual mailbox map (path relative to virtual_mailbox_base)
# Must end with Maildir/ to match Dovecot's mail_location = maildir:~/Maildir
local vmailbox="$data_path/config/vmailbox"
touch "$vmailbox"
grep -q "^$email" "$vmailbox" || echo "$email $domain/$user/Maildir/" >> "$vmailbox"
# Generate password hash
if [ -z "$password" ]; then
echo "Enter password for $email:"
read -s password
fi
# Add to dovecot users
local passfile="$data_path/config/users"
local hash=$(lxc-attach -n "$container" -- doveadm pw -s SHA512-CRYPT -p "$password" 2>/dev/null)
[ -z "$hash" ] && hash=$(openssl passwd -6 "$password")
grep -v "^$email:" "$passfile" > "${passfile}.tmp" 2>/dev/null
printf '%s\n' "$email:$hash" >> "${passfile}.tmp"
mv "${passfile}.tmp" "$passfile"
# Sync to Dovecot inside container
# Use correct uid:gid for vmail user (5000:5000) and proper mail path with userdb_mail
local mail_path="/var/mail/$domain/$user"
local dovecot_entry="$email:$hash:5000:5000::$mail_path::userdb_mail=maildir:$mail_path"
# Write to temp file first to avoid shell expansion issues with $6$ in hash
local tmpfile="/tmp/dovecot_entry_$$"
printf '%s\n' "$dovecot_entry" > "$tmpfile"
# Copy to container and merge with existing users file
lxc-attach -n "$container" -- sh -c "grep -v '^$email:' /etc/dovecot/users > /tmp/users.tmp 2>/dev/null || true"
cat "$tmpfile" | lxc-attach -n "$container" -- sh -c "cat >> /tmp/users.tmp && mv /tmp/users.tmp /etc/dovecot/users && chmod 644 /etc/dovecot/users && chown root:dovecot /etc/dovecot/users"
rm -f "$tmpfile"
# Postmap
lxc-attach -n "$container" -- postmap /etc/postfix/vmailbox 2>/dev/null
echo "User added: $email"
}
# Delete mail user
user_del() {
local email="$1"
[ -z "$email" ] && { echo "Usage: user_del <email@domain>"; return 1; }
local container=$(get_container)
local data_path=$(get_data_path)
# Remove from vmailbox
local vmailbox="$data_path/config/vmailbox"
sed -i "/^$email /d" "$vmailbox" 2>/dev/null
# Remove from passfile
local passfile="$data_path/config/users"
sed -i "/^$email:/d" "$passfile" 2>/dev/null
# Postmap
lxc-attach -n "$container" -- postmap /etc/postfix/vmailbox 2>/dev/null
echo "User deleted: $email (mailbox preserved)"
}
# List mail users
user_list() {
local data_path=$(get_data_path)
local passfile="$data_path/config/users"
if [ -f "$passfile" ]; then
echo "Mail Users:"
cut -d: -f1 "$passfile" | while read email; do
local domain=$(echo "$email" | cut -d@ -f2)
local user=$(echo "$email" | cut -d@ -f1)
local maildir="$data_path/mail/$domain/$user"
local size=$(du -sh "$maildir" 2>/dev/null | awk '{print $1}')
printf " %-40s %s\n" "$email" "${size:-0}"
done
else
echo "No users configured"
fi
}
# Change user password
user_passwd() {
local email="$1"
local password="$2"
[ -z "$email" ] && { echo "Usage: user_passwd <email@domain> [new_password]"; return 1; }
local container=$(get_container)
local data_path=$(get_data_path)
local passfile="$data_path/config/users"
grep -q "^$email:" "$passfile" || { echo "User not found: $email"; return 1; }
if [ -z "$password" ]; then
echo "Enter new password for $email:"
read -s password
fi
local hash=$(lxc-attach -n "$container" -- doveadm pw -s SHA512-CRYPT -p "$password" 2>/dev/null)
[ -z "$hash" ] && hash=$(openssl passwd -6 "$password")
# Update host passfile
sed -i "s|^$email:.*|$email:$hash|" "$passfile"
# Sync to Dovecot inside container
# Use correct uid:gid for vmail user (5000:5000) and proper mail path with userdb_mail
local user=$(echo "$email" | cut -d@ -f1)
local domain=$(echo "$email" | cut -d@ -f2)
local mail_path="/var/mail/$domain/$user"
# Build dovecot entry with proper format:
# user:password:uid:gid:gecos:home:shell:userdb_mail=maildir:/path
local dovecot_entry="$email:$hash:5000:5000::$mail_path::userdb_mail=maildir:$mail_path"
# Write to temp file first to avoid shell expansion issues with $6$ in hash
local tmpfile="/tmp/dovecot_entry_$$"
printf '%s\n' "$dovecot_entry" > "$tmpfile"
# Copy to container and merge with existing users file
lxc-attach -n "$container" -- sh -c "grep -v '^$email:' /etc/dovecot/users > /tmp/users.tmp 2>/dev/null || true"
cat "$tmpfile" | lxc-attach -n "$container" -- sh -c "cat >> /tmp/users.tmp && mv /tmp/users.tmp /etc/dovecot/users && chmod 644 /etc/dovecot/users && chown root:dovecot /etc/dovecot/users"
rm -f "$tmpfile"
echo "Password changed for: $email"
}
# Add alias
alias_add() {
local alias="$1"
local target="$2"
[ -z "$alias" ] || [ -z "$target" ] && { echo "Usage: alias_add <alias@domain> <target@domain>"; return 1; }
local container=$(get_container)
local data_path=$(get_data_path)
local valias="$data_path/config/valias"
touch "$valias"
grep -q "^$alias " "$valias" || echo "$alias $target" >> "$valias"
lxc-attach -n "$container" -- postmap /etc/postfix/valias 2>/dev/null
echo "Alias added: $alias$target"
}
# Delete alias
alias_del() {
local alias="$1"
[ -z "$alias" ] && { echo "Usage: alias_del <alias@domain>"; return 1; }
local container=$(get_container)
local data_path=$(get_data_path)
local valias="$data_path/config/valias"
if [ ! -f "$valias" ] || ! grep -q "^$alias " "$valias"; then
echo "Alias not found: $alias"
return 1
fi
sed -i "/^$alias /d" "$valias"
lxc-attach -n "$container" -- postmap /etc/postfix/valias 2>/dev/null
echo "Alias deleted: $alias"
}
# List aliases
alias_list() {
local data_path=$(get_data_path)
local valias="$data_path/config/valias"
if [ -f "$valias" ]; then
echo "Aliases:"
cat "$valias" | while read alias target; do
printf " %-40s → %s\n" "$alias" "$target"
done
else
echo "No aliases configured"
fi
}