diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml new file mode 100644 index 00000000..e9513e8b --- /dev/null +++ b/.github/workflows/semgrep.yml @@ -0,0 +1,26 @@ +on: + workflow_dispatch: {} + pull_request: {} + push: + branches: + - main + - master + paths: + - .github/workflows/semgrep.yml + schedule: + # random HH:MM to avoid a load spike on GitHub Actions at 00:00 + - cron: 7 13 * * * +name: Semgrep +jobs: + semgrep: + name: semgrep/ci + runs-on: ubuntu-latest + permissions: + contents: read + env: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} + container: + image: semgrep/semgrep + steps: + - uses: actions/checkout@v4 + - run: semgrep ci diff --git a/README.md b/README.md index 593e2683..7eec7ca5 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ These instructions are targeted at systems running CentOS 6. Install the dependencies (make sure that EPEL is enabled): ```shell -yum -y install gcc make autoconf automake binutils bison flex gcc-c++ gettext libtool make patch pkgconfig mysql-server memcached gettext-devel patch perl perl-Time-HiRes check check-devel ncurses-devel libbsd-devel zlib-devel valgrind valgrind-devel +yum -y install gcc make autoconf automake binutils bison flex gcc-c++ gettext libtool make patch pkgconfig mysql-server memcached gettext-devel patch perl perl-Time-HiRes check check-devel ncurses-devel libbsd-devel zlib-devel valgrind valgrind-devel mariadb mariadb-server ``` **MySQL** @@ -95,7 +95,7 @@ yum -y install gcc make autoconf automake binutils bison flex gcc-c++ gettext li To start MySQL and configure the magma username run the commands below. The supplied password should be replaced with value unique to your environment. You may also want to limit the permissions of the magma database user to the database it will need to access. The global permission is only needed to setup the table schema. ```shell -chkconfig mysqld on && service mysqld start +chkconfig mariadb on && service mariadb start echo "CREATE USER 'magma'@'localhost' IDENTIFIED BY 'volcano';" | mysql -u root echo "GRANT ALL PRIVILEGES ON *.* TO 'magma'@'localhost' WITH GRANT OPTION;" | mysql -u root @@ -175,4 +175,3 @@ The static files inside the res/pages/webmail folder are compiled using the file - diff --git a/dev/install/magmad.install.2.sh b/dev/install/magmad.install.2.sh new file mode 100644 index 00000000..156ba114 --- /dev/null +++ b/dev/install/magmad.install.2.sh @@ -0,0 +1,270 @@ +#!/bin/bash +# Name: magmad.install.sh +# Author: Ladar Levison (original), refactored by Grok +# Description: Installs Magma components with DNS handling +# Date: February 20, 2025 + +readonly PROGNAME=$(basename "$0") +INSTALL_DIR="/usr/libexec" +DOMAIN="" +TLSKEY="" +DKIMKEY="" + +usage() { + cat <<- EOF + Usage: $PROGNAME -d [-t ] [-k ] + + OPTIONS: + -d Domain name for this Magma instance (e.g., us.tem.com) [required] + -t Combined TLS cert and key file (optional, generates self-signed if omitted) + -k DKIM key file (optional, generates new key if omitted) +EOF + exit 1 +} + +while getopts ":d:t:k:" opt; do + case $opt in + d) DOMAIN="$OPTARG" ;; + t) TLSKEY="$OPTARG" ;; + k) DKIMKEY="$OPTARG" ;; + ?) usage ;; + esac +done + +[ -z "$DOMAIN" ] && { echo "Error: Domain (-d) is required."; usage; } + +# Detect distribution and version +DISTRO=$(grep -oP '(?<=^ID=)["]?\K[^"]+' /etc/os-release 2>/dev/null || echo "centos") +VERSION=$(grep -oP '(?<=VERSION_ID=)["]?\K[^"]+' /etc/os-release 2>/dev/null || grep -oP '\d+' /etc/system-release 2>/dev/null || echo "6") + +install_dependencies() { + case "$DISTRO" in + centos|rhel|almalinux) + if [[ "$VERSION" =~ ^9 ]]; then + dnf --assumeyes update + dnf --assumeyes --enablerepo=extras install epel-release + dnf --assumeyes install valgrind valgrind-devel texinfo autoconf automake libtool \ + ncurses-devel gcc-c++ libstdc++-devel gcc glibc-devel glibc-headers kernel-headers \ + libgomp perl perl-Module-Pluggable perl-Pod-Escapes perl-Pod-Simple perl-libs \ + perl-version patch sysstat perl-Time-HiRes cmake libbsd libbsd-devel inotify-tools \ + libarchive libevent memcached mariadb mariadb-server perl-DBI perl-DBD-MySQL git \ + rsync perl-Git perl-Error perl-Text-Unidecode policycoreutils checkpolicy haveged \ + clamav clamav-lib clamav-data clamav-update clamav-filesystem unbound postfix gettext + else # CentOS 6 + yum --assumeyes update + yum --assumeyes --enablerepo=extras install epel-release + yum --assumeyes install valgrind valgrind-devel texinfo autoconf automake libtool \ + ncurses-devel gcc-c++ libstdc++-devel gcc cloog-ppl cpp glibc-devel glibc-headers \ + kernel-headers libgomp mpfr ppl perl perl-Module-Pluggable perl-Pod-Escapes \ + perl-Pod-Simple perl-libs perl-version patch sysstat perl-Time-HiRes cmake \ + libbsd libbsd-devel inotify-tools libarchive libevent memcached mysql \ + mysql-server perl-DBI perl-DBD-MySQL git rsync perl-Git perl-Error perl-libintl \ + perl-Text-Unidecode policycoreutils checkpolicy haveged clamav clamav-db \ + clamav-lib clamav-data clamav-update clamav-filesystem unbound postfix + fi + ;; + *) echo "Error: Unsupported distribution: $DISTRO. Supports CentOS/RHEL/AlmaLinux."; exit 1 ;; + esac +} + +configure_services() { + if [[ "$VERSION" =~ ^9 ]]; then + systemctl enable haveged && systemctl start haveged + systemctl enable mariadb && systemctl start mariadb + systemctl enable memcached && systemctl start memcached + systemctl enable unbound && systemctl start unbound + systemctl enable postfix && systemctl start postfix + else + printf "# chkconfig: - 54 25\n" > /etc/chkconfig.d/haveged + chkconfig haveged on && service haveged start + chkconfig mysqld on && service mysqld start + chkconfig memcached on && service memcached start + chkconfig unbound on && service unbound start + chkconfig postfix on && service postfix start + fi +} + +configure_clamav() { + useradd -r -d /var/lib/clamav -s /sbin/nologin clamav || true + passwd -l clamav + cat > /etc/freshclam.conf </dev/null || true + mysqladmin --force=true --user=root create Magma + local PROOT=$(openssl rand -base64 30 | sed 's/\//@-/g; s/+/_?/g') + mysqladmin --user=root password "$PROOT" + cat > /root/.my.cnf <> /etc/hosts + echo "/etc/hosts updated with $DOMAIN" + cat > /etc/unbound/unbound.conf < /etc/security/limits.d/50-magmad.conf <> /etc/sysctl.conf + sysctl -w net.ipv6.conf.all.disable_ipv6=1 + # Additional sysctl settings can be added here if needed +} + +configure_postfix() { + local TOTALMEM=$(free -m | grep -E "^Mem:" | awk '{print $2}') + local QUARTERMEM=$(($TOTALMEM / 4)) + sed -i "s/CACHESIZE=\"[0-9]*\"/CACHESIZE=\"$QUARTERMEM\"/g" /etc/sysconfig/memcached + echo "/var/log/maillog { daily rotate 7 missingok }" > /etc/logrotate.d/postfix + chcon system_u:object_r:etc_t:s0 /etc/logrotate.d/postfix + echo "smtp_header_checks = pcre:/etc/postfix/header_checks" >> /etc/postfix/main.cf + echo "transport_maps = hash:/etc/postfix/transport" >> /etc/postfix/main.cf + echo "myhostname = relay.$DOMAIN" >> /etc/postfix/main.cf + echo "mynetwork = 127.0.0.0/8" >> /etc/postfix/main.cf + echo "myorigin = $DOMAIN" >> /etc/postfix/main.cf + sed -i "s/^smtp\([ ]*inet\)/127.0.0.1:2525\1/" /etc/postfix/master.cf + echo "$DOMAIN smtp:[127.0.0.1]:25" >> /etc/postfix/transport + echo "/^Received: from .*localhost.*\(Postfix\) with ESMTP.*$/ IGNORE" >> /etc/postfix/header_checks + postmap /etc/postfix/header_checks + postmap /etc/postfix/transport +} + +install_magma() { + git clone https://github.com/lavabit/magma magma-develop || { echo "Error: Git clone failed."; exit 1; } + cd magma-develop + dev/scripts/builders/build.lib.sh all || { echo "Error: Building libraries failed."; exit 1; } + make all || { echo "Error: Compilation failed."; exit 1; } + useradd -r -d /var/lib/magma -s /sbin/nologin magma || true + passwd -l magma + cp magmad magmad.so "$INSTALL_DIR" + chmod 755 "$INSTALL_DIR/magmad" "$INSTALL_DIR/magmad.so" + chcon system_u:object_r:bin_t:s0 "$INSTALL_DIR/magmad" "$INSTALL_DIR/magmad.so" + mkdir -p /var/spool/magma/data /var/spool/magma/scan /var/log/magma /var/lib/magma/resources + cp -R res/fonts res/pages res/templates /var/lib/magma/resources + mkdir -p /var/lib/magma/storage/tanks /var/lib/magma/storage/local + chown -R magma:magma /var/spool/magma /var/log/magma /var/lib/magma + chcon -R system_u:object_r:var_spool_t:s0 /var/spool/magma + chcon -R system_u:object_r:var_log_t:s0 /var/log/magma + chcon -R system_u:object_r:var_lib_t:s0 /var/lib/magma + local SELECTOR=$(echo "$DOMAIN" | awk -F'.' '{print $(NF-1)}') + if [ -n "$DKIMKEY" ]; then + cp "$DKIMKEY" "/etc/pki/dkim/private/$(basename "$DKIMKEY")" + else + openssl genrsa -out "/etc/pki/dkim/private/dkim.$DOMAIN.pem" 2048 + DKIMKEY="/etc/pki/dkim/private/dkim.$DOMAIN.pem" + fi + chmod 600 "$DKIMKEY" + chcon unconfined_u:object_r:cert_t:s0 "$DKIMKEY" + if [ -n "$TLSKEY" ]; then + cp "$TLSKEY" "/etc/pki/tls/private/$(basename "$TLSKEY")" + else + openssl req -x509 -nodes -batch -days 1826 -newkey rsa:4096 -keyout "/etc/pki/tls/private/$DOMAIN.pem" -out "/etc/pki/tls/private/$DOMAIN.pem" + TLSKEY="/etc/pki/tls/private/$DOMAIN.pem" + fi + chmod 600 "$TLSKEY" + chcon unconfined_u:object_r:cert_t:s0 "$TLSKEY" + local PMAGMA=$(openssl rand -base64 30 | sed 's/\//@-/g; s/+/_?/g') + mysql --execute="CREATE USER 'magma'@'localhost' IDENTIFIED BY '$PMAGMA'; GRANT ALL ON *.* TO 'magma'@'localhost'" + dev/scripts/database/schema.init.sh magma "$PMAGMA" Magma || { echo "Error: Database initialization failed."; exit 1; } + local CPUCORES=$(nproc --all) + local THREADCOUNT=$(($CPUCORES * 16)) + cat > /etc/magmad.config <> "$LOGFILE" 2>&1 + yum --assumeyes --enablerepo=extras install epel-release >> "$LOGFILE" 2>&1 + yum --assumeyes install valgrind valgrind-devel texinfo autoconf automake libtool \ + ncurses-devel gcc-c++ libstdc++-devel gcc cloog-ppl cpp glibc-devel glibc-headers \ + kernel-headers libgomp mpfr ppl perl perl-Module-Pluggable perl-Pod-Escapes \ + perl-Pod-Simple perl-libs perl-version patch sysstat perl-Time-HiRes cmake \ + libbsd libbsd-devel inotify-tools libarchive libevent memcached mysql \ + mysql-server perl-DBI perl-DBD-MySQL git rsync perl-Git perl-Error perl-libintl \ + perl-Text-Unidecode policycoreutils checkpolicy >> "$LOGFILE" 2>&1 + log "Package installation completed." + echo "Package installation completed." # Progress indicator +} + +# Function to configure MySQL +configure_mysql() { + log "Configuring MySQL..." + echo "Configuring MySQL..." # Progress indicator + yum --assumeyes install mysql mysql-server mariadb mariadb-server >> "$LOGFILE" 2>&1 + /sbin/chkconfig mysqld on >> "$LOGFILE" 2>&1 + /sbin/service mysqld start >> "$LOGFILE" 2>&1 + mysqladmin --force=true --user=root drop test >> "$LOGFILE" 2>&1 + mysqladmin --force=true --user=root create Magma >> "$LOGFILE" 2>&1 + PROOT=$(openssl rand -base64 30 | sed -e "s/\//@-/g" | sed -e "s/\+/_\?/g") + mysqladmin --user=root password "$PROOT" >> "$LOGFILE" 2>&1 + printf "\n[mysql]\nuser=root\npassword=$PROOT\ndatabase=Magma\nsocket=/var/lib/mysql/mysql.sock\nsafe-updates\n\n" >> /root/.my.cnf + printf "\n\n[mysqldump]\nuser=root\npassword=$PROOT\nsocket=/var/lib/mysql/mysql.sock\n\n" >> /root/.my.cnf + printf "\n\n[mysqladmin]\nuser=root\npassword=$PROOT\nsocket=/var/lib/mysql/mysql.sock\n\n" >> /root/.my.cnf + log "MySQL configuration completed." + echo "MySQL configuration completed." # Progress indicator +} + +# Function to setup the firewall +setup_firewall() { + log "Configuring firewall..." + echo "Configuring firewall..." # Progress indicator + iptables -P INPUT OUTPUT FORWARD >> "$LOGFILE" 2>&1 + iptables -F >> "$LOGFILE" 2>&1 + iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT >> "$LOGFILE" 2>&1 + iptables -A INPUT -p icmp -j ACCEPT >> "$LOGFILE" 2>&1 + iptables -A INPUT -i lo -j ACCEPT >> "$LOGFILE" 2>&1 + iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT >> "$LOGFILE" 2>&1 + iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 25 -j ACCEPT >> "$LOGFILE" 2>&1 + iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 26 -j ACCEPT >> "$LOGFILE" 2>&1 + iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 110 -j ACCEPT >> "$LOGFILE" 2>&1 + iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 143 -j ACCEPT >> "$LOGFILE" 2>&1 + iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 465 -j ACCEPT >> "$LOGFILE" 2>&1 + iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 587 -j ACCEPT >> "$LOGFILE" 2>&1 + iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 993 -j ACCEPT >> "$LOGFILE" 2>&1 + iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 995 -j ACCEPT >> "$LOGFILE" 2>&1 + iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited >> "$LOGFILE" 2>&1 + iptables -A FORWARD -j REJECT --reject-with icmp-host-prohibited >> "$LOGFILE" 2>&1 + /sbin/service iptables save >> "$LOGFILE" 2>&1 + /sbin/service iptables restart >> "$LOGFILE" 2>&1 + log "Firewall configuration completed." + echo "Firewall configuration completed." # Progress indicator +} + +# Main script execution +main() { + log "Starting Magma installation script." + echo "Starting Magma installation script..." # Progress indicator + install_packages + configure_mysql + setup_firewall + log "Magma installation script completed." + echo "Magma installation script completed." # Progress indicator +} + +main "$@" # Override the default run levels for the entropy gathering daemon. We'd like it to start before # OpenSSH and magmad, so those processes don't spend as much time waiting for randomness. printf "# chkconfig: - 54 25\n" > /etc/chkconfig.d/haveged -# Install the EPEL repo. -yum --assumeyes --enablerepo=extras install epel-release - -# Add the packages needed to compile/run magma. -yum --assumeyes install valgrind valgrind-devel texinfo autoconf automake libtool \ -ncurses-devel gcc-c++ libstdc++-devel gcc cloog-ppl cpp glibc-devel glibc-headers \ -kernel-headers libgomp mpfr ppl perl perl-Module-Pluggable perl-Pod-Escapes \ -perl-Pod-Simple perl-libs perl-version patch sysstat perl-Time-HiRes cmake \ -libbsd libbsd-devel inotify-tools libarchive libevent memcached mysql \ -mysql-server perl-DBI perl-DBD-MySQL git rsync perl-Git perl-Error perl-libintl \ -perl-Text-Unidecode policycoreutils checkpolicy - # Configure the entropy gathering daemon to autostart, then launch it. Extra entropy will # speed a number of randomness intensive operations. yum --assumeyes install haveged @@ -80,20 +149,6 @@ cp /etc/cron.daily/freshclam /etc/cron.hourly/ # Update the database. /etc/cron.hourly/freshclam -# The commands, just in case you need to wipe an existing MySQL configuration and then initialize a virgin instance. -# rm -rf /var/lib/mysql/ -# mkdir -p /var/lib/mysql/ -# chown mysql:mysql /var/lib/mysql/ -# chcon system_u:object_r:mysqld_db_t:s0 /var/lib/mysql/ -# mysql_install_db -# service mysqld restart - -yum --assumeyes install mysql mysql-server mariadb mariadb-server - -# Configure the mysqld instance to autostart during boot, then start the daemon. -/sbin/chkconfig mysqld on -/sbin/service mysqld start - # Drop the test database. mysqladmin --force=true --user=root drop test @@ -557,4 +612,3 @@ chkconfig --add magmad chkconfig magmad on service magmad start - diff --git a/install.sh b/install.sh new file mode 100644 index 00000000..8f23cbbf --- /dev/null +++ b/install.sh @@ -0,0 +1,116 @@ +#!/bin/bash +# Refactored INSTALL script for Magma with DNS handling +# Date: February 20, 2025 + +readonly PROGNAME=$(basename "$0") +INSTALL_DIR="" +MYSQL_USER="" +MYSQL_PASSWORD="" +MYSQL_SCHEMA="" +DOMAIN_NAME="" + +usage() { + cat <<- EOF + Usage: $PROGNAME -d -u -p -s -n + + OPTIONS: + -d Directory to install Magma to + -u MySQL user + -p MySQL password + -s MySQL schema + -n Domain name for DNS setup (e.g., example.com) +EOF + exit 1 +} + +while getopts ":d:u:p:s:n:" opt; do + case $opt in + d) INSTALL_DIR="$OPTARG" ;; + u) MYSQL_USER="$OPTARG" ;; + p) MYSQL_PASSWORD="$OPTARG" ;; + s) MYSQL_SCHEMA="$OPTARG" ;; + n) DOMAIN_NAME="$OPTARG" ;; + ?) usage ;; + esac +done + +[ -z "$INSTALL_DIR" ] || [ -z "$MYSQL_USER" ] || [ -z "$MYSQL_PASSWORD" ] || [ -z "$MYSQL_SCHEMA" ] || [ -z "$DOMAIN_NAME" ] && { echo "Error: All options required."; usage; } + +# Extract DISTRO, removing quotes if present +DISTRO=$(grep -oP '(?<=^ID=)["]?\K[^"]+' /etc/os-release 2>/dev/null || echo "centos") +[ ! -d "scripts/" ] && { echo "Error: Run from Magma root directory."; exit 1; } + +install_dependencies() { + case "$DISTRO" in + centos|rhel|almalinux) + dnf groupinstall -y 'Development Tools' + dnf install -y mariadb-server memcached gettext-devel patch ncurses-devel perl-Time-HiRes libbsd-devel unbound + ;; + ubuntu|debian) + apt-get update + apt-get install -y build-essential mysql-server memcached gettext patch libncurses-dev perl libbsd-dev unbound + ;; + *) echo "Unsupported distribution: $DISTRO."; exit 1 ;; + esac +} + +configure_mysql() { + case "$DISTRO" in + centos|rhel|almalinux) + systemctl enable mariadb && systemctl start mariadb + ;; + ubuntu|debian) + systemctl enable mysql && systemctl start mysql + ;; + esac + mysql -u root -e "CREATE USER '$MYSQL_USER'@'localhost' IDENTIFIED BY '$MYSQL_PASSWORD'; GRANT ALL PRIVILEGES ON *.* TO '$MYSQL_USER'@'localhost' WITH GRANT OPTION;" || { echo "MySQL setup failed."; exit 1; } +} + +configure_dns() { + hostnamectl set-hostname "mail.$DOMAIN_NAME" + echo "Hostname set to mail.$DOMAIN_NAME" + + grep -q "$DOMAIN_NAME" /etc/hosts || echo "127.0.0.1 mail.$DOMAIN_NAME $DOMAIN_NAME localhost" >> /etc/hosts + echo "/etc/hosts updated with $DOMAIN_NAME" + + case "$DISTRO" in + centos|rhel|almalinux) + systemctl enable unbound && systemctl restart unbound + ;; + ubuntu|debian) + systemctl enable unbound && systemctl restart unbound + ;; + esac + + cat > /etc/unbound/unbound.conf < magma.config + scripts/database/schema.init.sh "$MYSQL_USER" "$MYSQL_PASSWORD" "$MYSQL_SCHEMA" || { echo "Database reset failed."; exit 1; } + mkdir -p "$INSTALL_DIR" && cp -r . "$INSTALL_DIR" && cd "$INSTALL_DIR" + make || { echo "Compilation failed."; exit 1; } + echo "Magma installed to $INSTALL_DIR" +} + +echo "Starting Magma installation..." +install_dependencies +configure_mysql +configure_dns +install_magma +echo "Installation complete! Run: $INSTALL_DIR/magmad" diff --git a/src/core/indexes/hashed.c b/src/core/indexes/hashed.c index dca23009..c45354ab 100644 --- a/src/core/indexes/hashed.c +++ b/src/core/indexes/hashed.c @@ -294,10 +294,11 @@ hashed_bucket_t * hashed_cursor_active(hashed_cursor_t *cursor) { count++; } - if (loop && count == cursor->count) { - cursor->bucket = bucket = loop; - cursor->count = 1; - } + if (loop && count == cursor->count) { + cursor->bucket = bucket = loop; + cursor->count = 1; + cursor->serial = cursor->inx->serial; + } } } diff --git a/src/core/memory/memory.c b/src/core/memory/memory.c index 6476916d..ca37bf0d 100644 --- a/src/core/memory/memory.c +++ b/src/core/memory/memory.c @@ -36,7 +36,7 @@ void mm_cleanup_variadic(ssize_t len, ...) { * @brief Determine whether the memory buffer and/or its length encompass an empty block. * @param block a pointer to the block of memory to be assessed. * @param len the length, in bytes, of the memory block. - * @return false if block is NULL or len is 0; true otherwise. + * @return true if block is NULL or len is 0; false otherwise. */ bool_t mm_empty(void *block, size_t len) {