id: os_ssh_server_alive_count_max_configure
title: Set SSH Active Server Alive Maximum to $ODV
discussion: |
  SSH _MUST_ be configured with an Active Server Alive Maximum Count set to $ODV. Terminating an idle session within a short time period reduces the window of opportunity for unauthorized personnel to take control of a management session enabled on the console or console port that has been left unattended. In addition, quickly terminating an idle session or an incomplete login attempt will also free up resources committed by the managed network element.

  NOTE: /etc/ssh/ssh_config will be automatically modified to its original state following any update or major upgrade to the operating system.

  NOTE: On macOS 15.2 and higher the SSH configuration can be reset to the macOS default by running /usr/libexec/reset-ssh-configuration.
references:
  nist:
    cce:
      macos_27:
        - CCE-XXXXX-X
      macos_26:
        - CCE-95305-9
      macos_15:
        - CCE-94300-1
      macos_14:
        - CCE-92895-2
    800-53r5:
      - SC-10
    800-171r3:
      - 03.13.09
  disa:
    cci:
      - CCI-001133
    srg:
      - SRG-OS-000163-GPOS-00072
    disa_stig:
      macos_26:
        - APPL-26-000140
      macos_15:
        - APPL-15-000140
      macos_14:
        - APPL-14-000140
    cmmc:
      - SC.L2-3.13.9
platforms:
  macOS:
    '27.0': {}
    '26.0':
      benchmarks:
        - name: disa_stig
          severity: medium
      enforcement_info:
        fix:
          shell: |
            include_dir=$(/usr/bin/awk '/^Include/ {print $2}' /etc/ssh/ssh_config | /usr/bin/tr -d '*')

            ssh_config=("ServerAliveCountMax $ODV")

            ssh_setting=$(echo $ssh_config | /usr/bin/cut -d " " -f1)
            /usr/bin/grep -qEi "^$ssh_setting" "${include_dir}01-mscp-ssh.conf" && /usr/bin/sed -i "" "s/^$ssh_setting.*/${ssh_config}/" "${include_dir}01-mscp-ssh.conf" || echo "$ssh_config" >> "${include_dir}01-mscp-ssh.conf"
            for u in $(/usr/bin/dscl . list /users shell | /usr/bin/egrep -v '(^_)|(root)|(/usr/bin/false)' | /usr/bin/awk '{print $1}'); do
              config=$(/usr/bin/sudo -u $u /usr/bin/ssh -Gv . 2>&1)
              configfiles=$(echo "$config" | /usr/bin/awk '/Reading configuration data/ {print $NF}'| /usr/bin/tr -d '\r')
              configarray=( ${(f)configfiles} )
              if ! echo $config | /usr/bin/grep -q -i "$ssh_config" ; then
                for c in $configarray; do
                  if [[ "$c" == "/etc/ssh/crypto.conf" ]]; then
                    continue
                  fi

                  /usr/bin/sudo -u $u /usr/bin/grep -qEi "^$ssh_setting" "$c" && /usr/bin/sed -i "" "s/^$ssh_setting.*/${ssh_config}/I" "$c"
                  if [[ "$c" =~ ".ssh/config" ]]; then
                    if /usr/bin/grep -qEi "$ssh_setting" "$c" 2> /dev/null; then
                      old_file=$(cat ~$u/.ssh/config)
                      echo "$ssh_config" > ~$u/.ssh/config
                      echo "$old_file" >> ~$u/.ssh/config
                    fi
                  fi
                done
              fi
            done
    '15.0':
      benchmarks:
        - name: disa_stig
          severity: medium
      enforcement_info:
        fix:
          shell: |
            include_dir=$(/usr/bin/awk '/^Include/ {print $2}' /etc/ssh/ssh_config | /usr/bin/tr -d '*')

            ssh_config=("ServerAliveCountMax $ODV")

            ssh_setting=$(echo $ssh_config | /usr/bin/cut -d " " -f1)
            /usr/bin/grep -qEi "^$ssh_setting" "${include_dir}01-mscp-ssh.conf" && /usr/bin/sed -i "" "s/^$ssh_setting.*/${ssh_config}/" "${include_dir}01-mscp-ssh.conf" || echo "$ssh_config" >> "${include_dir}01-mscp-ssh.conf"
            for u in $(/usr/bin/dscl . list /users shell | /usr/bin/egrep -v '(^_)|(root)|(/usr/bin/false)' | /usr/bin/awk '{print $1}'); do
              config=$(/usr/bin/sudo -u $u /usr/bin/ssh -Gv . 2>&1)
              configfiles=$(echo "$config" | /usr/bin/awk '/Reading configuration data/ {print $NF}'| /usr/bin/tr -d '\r')
              configarray=( ${(f)configfiles} )
              if ! echo $config | /usr/bin/grep -q -i "$ssh_config" ; then
                for c in $configarray; do
                  if [[ "$c" == "/etc/ssh/crypto.conf" ]]; then
                    continue
                  fi

                  /usr/bin/sudo -u $u /usr/bin/grep -qEi "^$ssh_setting" "$c" && /usr/bin/sed -i "" "s/^$ssh_setting.*/${ssh_config}/I" "$c"
                  if [[ "$c" =~ ".ssh/config" ]]; then
                    if /usr/bin/grep -qEi "$ssh_setting" "$c" 2> /dev/null; then
                      old_file=$(cat ~$u/.ssh/config)
                      echo "$ssh_config" > ~$u/.ssh/config
                      echo "$old_file" >> ~$u/.ssh/config
                    fi
                  fi
                done
              fi
            done
    enforcement_info:
      check:
        shell: |-
          ret="pass"
          for u in $(/usr/bin/dscl . -list /Users UniqueID | /usr/bin/awk '$2 > 500 {print $1}'); do
            sshCheck=$(/usr/bin/sudo -u $u /usr/bin/ssh -G . | /usr/bin/grep -c "^serveralivecountmax $ODV")
            if [[ "$sshCheck" == "0" ]]; then
              ret="fail"
              break
            fi
          done
          /bin/echo $ret
        result:
          string: pass
      fix:
        shell: |
          include_dir=$(/usr/bin/awk '/^Include/ {print $2}' /etc/ssh/ssh_config | /usr/bin/tr -d '*')

          ssh_config=("ServerAliveCountMax $ODV")

          ssh_setting=$(echo $ssh_config | /usr/bin/cut -d " " -f1)
          /usr/bin/grep -qEi "^$ssh_setting" "${include_dir}01-mscp-ssh.conf" && /usr/bin/sed -i "" "s/^$ssh_setting.*/${ssh_config}/" "${include_dir}01-mscp-ssh.conf" || echo "$ssh_config" >> "${include_dir}01-mscp-ssh.conf"
          for u in $(/usr/bin/dscl . list /users shell | /usr/bin/egrep -v '(^_)|(root)|(/usr/bin/false)' | /usr/bin/awk '{print $1}'); do
            config=$(/usr/bin/sudo -u $u /usr/bin/ssh -Gv . 2>&1)
            configfiles=$(echo "$config" | /usr/bin/awk '/Reading configuration data/ {print $NF}'| /usr/bin/tr -d '\r')
            configarray=( ${(f)configfiles} )
            if ! echo $config | /usr/bin/grep -q -i "$ssh_config" ; then
              for c in $configarray; do
                if [[ "$c" == "/etc/ssh/crypto.conf" ]]; then
                  continue
                fi

                /usr/bin/sudo -u $u /usr/bin/grep -qEi "^$ssh_setting" "$c" && /usr/bin/sed -i "" "s/^$ssh_setting.*/${ssh_config}/I" "$c"
                if [[ "$c" =~ ".ssh/config" ]]; then
                  if /usr/bin/grep -qEi "$ssh_setting" "$c" 2> /dev/null; then
                    old_file=$(cat ~$u/.ssh/config)
                    echo "$ssh_config" > ~$u/.ssh/config
                    echo "$old_file" >> ~$u/.ssh/config
                  fi
                fi
              done
            fi
          done
odv:
  hint:
    datatype: number
    description: Number of seconds, e.g. 0
    validation:
      min: 0
  recommended: 0
  disa_stig: 0
tags:
  - 800-53r5_moderate
  - 800-53r5_high
  - 800-171
  - cnssi-1253_low
  - cnssi-1253_high
  - cmmc_lvl2
  - cnssi-1253_moderate
