#!/bin/bash
# =============================================================================
# regen_ldap_cert.sh
# Regenerates the self-signed LDAP TLS cert (CN read from /opt/app/cert.txt),
# replacing the cert already in use (set up by setup_ldaps.sh), and applies
# it to slapd's TLS config. Restarts slapd and httpd so the new cert
# actually takes effect everywhere.
#
# Includes explicit BasicConstraints/KeyUsage/ExtendedKeyUsage/SAN extensions
# so the cert is issued as a proper leaf/server cert rather than defaulting
# to CA:TRUE. SAN type (IP vs DNS) is auto-detected based on whether the CN
# is a literal IP address.
# =============================================================================

SSL_DIR="/etc/ldap/ssl"
CERT="$SSL_DIR/ldap.crt"
KEY="$SSL_DIR/ldap.key"
CN_FILE="/opt/app/cert.txt"
LDAP_CLIENT_CONF="/etc/ldap/ldap.conf"
TLS_LDIF="/tmp/tls_config.ldif"

# 1. Read CN from file, fallback to "localhost"
if [[ -f "$CN_FILE" && -s "$CN_FILE" ]]; then
  CERT_CN=$(head -n 1 "$CN_FILE" | xargs)
  echo "Read CN from $CN_FILE: $CERT_CN"
else
  CERT_CN="localhost"
  echo "CN file ($CN_FILE) not found or empty. Falling back to: $CERT_CN"
fi

# 2. Determine correct SAN type: IP address literal vs DNS hostname
if [[ "$CERT_CN" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
  SAN="IP:$CERT_CN"
  echo "CN looks like an IP address - using SAN type IP:$CERT_CN"
else
  SAN="DNS:$CERT_CN"
  echo "CN looks like a hostname - using SAN type DNS:$CERT_CN"
fi

# 3. Generate cert (overwrites the cert already in use)
echo "Creating SSL directory: $SSL_DIR"
mkdir -p "$SSL_DIR"

echo "Re-generating self-signed certificate (10 years) for CN=$CERT_CN..."
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
  -keyout "$KEY" \
  -out    "$CERT" \
  -subj "/C=US/ST=State/L=City/O=Cohesive/CN=$CERT_CN" \
  -addext "basicConstraints=critical,CA:FALSE" \
  -addext "keyUsage=critical,digitalSignature,keyEncipherment" \
  -addext "extendedKeyUsage=serverAuth" \
  -addext "subjectAltName=$SAN"

# 4. Fix ownership/permissions so slapd (running as openldap) can read the key
chown -R openldap:openldap "$SSL_DIR"
chmod 750 "$SSL_DIR"
chmod 640 "$KEY" "$CERT"
echo "Certificate generated and permissions set for openldap user."

# 5. Ensure other libldap consumers (LAM) trust this cert
if [[ ! -f "$LDAP_CLIENT_CONF" ]]; then
  echo "Creating $LDAP_CLIENT_CONF with TLS_REQCERT never..."
  mkdir -p /etc/ldap
  echo "TLS_REQCERT never" > "$LDAP_CLIENT_CONF"
elif ! grep -q '^TLS_REQCERT' "$LDAP_CLIENT_CONF"; then
  echo "Adding TLS_REQCERT never to existing $LDAP_CLIENT_CONF..."
  echo "TLS_REQCERT never" >> "$LDAP_CLIENT_CONF"
else
  echo "$LDAP_CLIENT_CONF already has a TLS_REQCERT setting - leaving as-is."
fi

# 6. Apply the new cert to slapd's TLS config (replaces the cert already
#    referenced in cn=config from setup_ldaps.sh)
echo "Applying new cert to slapd's TLS config..."
cat > "$TLS_LDIF" <<EOF
dn: cn=config
changetype: modify
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: ${CERT}
-
replace: olcTLSCertificateFile
olcTLSCertificateFile: ${CERT}
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: ${KEY}
EOF

if ldapmodify -Y EXTERNAL -H ldapi:/// -f "$TLS_LDIF" 2>&1; then
  echo "slapd TLS config updated successfully."
else
  echo "WARNING: ldapmodify returned an error - check /var/log/supervisor/slapd.log."
fi
rm -f "$TLS_LDIF"

# 7. Restart slapd so it picks up the new cert file contents.
#    (The file path doesn't change, so slapd won't reread it without a
#    restart even though the LDIF above was applied.)
if command -v supervisorctl &>/dev/null && supervisorctl status slapd &>/dev/null; then
  echo "Restarting slapd to load the new certificate..."
  supervisorctl restart slapd
else
  echo "WARNING: supervisorctl not available - restart slapd manually for the new cert to take effect."
fi

# 8. Restart httpd so PHP/LAM picks up the ldap.conf trust change
if command -v supervisorctl &>/dev/null && supervisorctl status httpd &>/dev/null; then
  echo "Restarting httpd so PHP/LAM picks up the TLS trust config..."
  supervisorctl restart httpd
else
  echo "WARNING: supervisorctl not available - restart httpd manually if LAM was already running."
fi

echo "Done. New cert CN=$CERT_CN is now active for slapd and trusted by LAM."